mongoose httpserver webcommand

说明

在mongoose http server的基础上允许在URL栏输入command,返回输出结果

eg:

localhost:8000/command: ls

其中/command:为关键字代表之后的为要执行的命令

 

main_webcommand.c

c 复制代码
// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved

#include <signal.h>
#include "mongoose.h"

static int s_debug_level = MG_LL_INFO;
static const char *s_root_dir = ".";
static const char *s_listening_address = "http://0.0.0.0:8000";
static const char *s_enable_hexdump = "no";
static const char *s_ssi_pattern = "#.html";
static const char *s_upload_dir = NULL;  // File uploads disabled by default

// Handle interrupts, like Ctrl-C
static int s_signo;
static void signal_handler(int signo) {
  s_signo = signo;
}

// Event handler for the listening connection.
// Simply serve static files from `s_root_dir`
static void cb(struct mg_connection *c, int ev, void *ev_data) {
  if (ev == MG_EV_HTTP_MSG) {
    struct mg_http_message *hm = ev_data, send_hm; 
    memset(&send_hm, 0, sizeof(send_hm));

    if (mg_match(hm->uri, mg_str("/upload"), NULL)) {
      // Serve file upload
      if (s_upload_dir == NULL) {
        mg_http_reply(c, 403, "", "Denied: file upload directory not set\n");
      } else {
        struct mg_http_part part;
        size_t pos = 0, total_bytes = 0, num_files = 0;
        while ((pos = mg_http_next_multipart(hm->body, pos, &part)) > 0) {
          char path[MG_PATH_MAX];
          MG_INFO(("Chunk name: [%.*s] filename: [%.*s] length: %lu bytes",
                   part.name.len, part.name.ptr, part.filename.len,
                   part.filename.ptr, part.body.len));
          mg_snprintf(path, sizeof(path), "%s/%.*s", s_upload_dir,
                      part.filename.len, part.filename.ptr);
          if (mg_path_is_sane(path)) {
            mg_file_write(&mg_fs_posix, path, part.body.ptr, part.body.len);
            total_bytes += part.body.len;
            num_files++;
          } else {
            MG_ERROR(("Rejecting dangerous path %s", path));
          }
        }
        mg_http_reply(c, 200, "", "Uploaded %lu files, %lu bytes\n", num_files,
                      total_bytes);
      }
    } else {
      // Serve web root directory
      struct mg_http_serve_opts opts = {0};
      opts.root_dir = s_root_dir;
      opts.ssi_pattern = s_ssi_pattern;
      if (hm->uri.len > 9 && strncmp("/command:", hm->uri.ptr, 9) == 0)
      {
        #define URI_SIZE 256
        char command[URI_SIZE] = {'\0'};
        mg_url_decode(hm->uri.ptr+9, hm->uri.len-9, command, URI_SIZE, 0);
        #undef URI_SIZE
        FILE* o_cmd = popen(command, "r");
        if (!o_cmd)
        {
          MG_ERROR(("exec command failed"));
          mg_http_reply(c, 500, "", "");
          goto end;
        }
        // #define BUFSIZ 10
        char* out_buf = calloc(1 , BUFSIZ);
        if (!out_buf)
        {
          MG_ERROR(("mem failed"));
          mg_http_reply(c, 503, "", "");
          goto end;
        }
        int n_read = fread(out_buf, 1, BUFSIZ-1, o_cmd);
        int content_len = 0;
        if (out_buf[0] != '\0') {
          mg_http_reply(c, 200, "", "%s", out_buf);
          content_len += n_read;
        } else {
          mg_http_reply(c, 200, "", "you command has no output or command error");
        }
        while (!feof(o_cmd))
        {
          n_read = fread(out_buf, 1, BUFSIZ-1, o_cmd);
          out_buf[n_read] = 0;
          mg_http_write_chunk(c, out_buf, n_read);
          content_len += n_read;
        }
        if (content_len)
        {
          char cont_len_str[11] = {0};
          snprintf(cont_len_str, 10, "%d", content_len);
          mg_http_parse((const char*)c->send.buf, c->send.len, &send_hm);
          struct mg_str* cl = mg_http_get_header(&send_hm, "Content-Length");
          memcpy((void*)(cl->ptr), cont_len_str, strlen(cont_len_str));
        }
        free(out_buf);
        end:  // that's ok
        pclose(o_cmd);
      }
      else
      {
        mg_http_serve_dir(c, hm, &opts);
      }
    }

    // Log request
    MG_INFO(("%.*s %.*s %lu -> %.*s %lu", hm->method.len, hm->method.ptr,
             hm->uri.len, hm->uri.ptr, hm->body.len, 3, c->send.buf + 9,
             c->send.len));
  }
}

static void usage(const char *prog) {
  fprintf(stderr,
          "Mongoose v.%s\n"
          "Usage: %s OPTIONS\n"
          "  -H yes|no - enable traffic hexdump, default: '%s'\n"
          "  -S PAT    - SSI filename pattern, default: '%s'\n"
          "  -d DIR    - directory to serve, default: '%s'\n"
          "  -l ADDR   - listening address, default: '%s'\n"
          "  -u DIR    - file upload directory, default: unset\n"
          "  -v LEVEL  - debug level, from 0 to 4, default: %d\n",
          MG_VERSION, prog, s_enable_hexdump, s_ssi_pattern, s_root_dir,
          s_listening_address, s_debug_level);
  exit(EXIT_FAILURE);
}

int main(int argc, char *argv[]) {
  char path[MG_PATH_MAX] = ".";
  struct mg_mgr mgr;
  struct mg_connection *c;
  int i;

  // Parse command-line flags
  for (i = 1; i < argc; i++) {
    if (strcmp(argv[i], "-d") == 0) {
      s_root_dir = argv[++i];
    } else if (strcmp(argv[i], "-H") == 0) {
      s_enable_hexdump = argv[++i];
    } else if (strcmp(argv[i], "-S") == 0) {
      s_ssi_pattern = argv[++i];
    } else if (strcmp(argv[i], "-l") == 0) {
      s_listening_address = argv[++i];
    } else if (strcmp(argv[i], "-u") == 0) {
      s_upload_dir = argv[++i];
    } else if (strcmp(argv[i], "-v") == 0) {
      s_debug_level = atoi(argv[++i]);
    } else {
      usage(argv[0]);
    }
  }

  // Root directory must not contain double dots. Make it absolute
  // Do the conversion only if the root dir spec does not contain overrides
  if (strchr(s_root_dir, ',') == NULL) {
    realpath(s_root_dir, path);
    s_root_dir = path;
  }

  // Initialise stuff
  signal(SIGINT, signal_handler);
  signal(SIGTERM, signal_handler);
  mg_log_set(s_debug_level);
  mg_mgr_init(&mgr);
  if ((c = mg_http_listen(&mgr, s_listening_address, cb, &mgr)) == NULL) {
    MG_ERROR(("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
              s_listening_address));
    exit(EXIT_FAILURE);
  }
  if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;

  // Start infinite event loop
  MG_INFO(("Mongoose version : v%s", MG_VERSION));
  MG_INFO(("Listening on     : %s", s_listening_address));
  MG_INFO(("Web root         : [%s]", s_root_dir));
  MG_INFO(("Upload dir       : [%s]", s_upload_dir ? s_upload_dir : "unset"));
  while (s_signo == 0) mg_mgr_poll(&mgr, 1000);
  mg_mgr_free(&mgr);
  MG_INFO(("Exiting on signal %d", s_signo));
  return 0;
}

参考链接:

https://github.com/cesanta/mongoose/blob/master/examples/http-server/main.c

相关推荐
Cry丶1 小时前
ubuntu安装vsftpd
服务器·网络·ubuntu
SHENGWEI胜为4 小时前
交换机端口显示正常,终端却获取不到 IP 地址?从 DHCP 流程定位故障
服务器·网络·测试工具·缓存·通信工程
IMPYLH6 小时前
Linux 系统备份与镜像
linux·服务器·网络
淘气包海鸟7 小时前
水声网络框架
网络·ns3·水
国科安芯8 小时前
星间激光通信终端CANFD控制网络的时延确定性与辐射可靠性
网络·嵌入式硬件·信息与通信·canfd·低轨卫星·商业航天·抗辐射
中屹指纹浏览器svip9 小时前
网络抖动会标记账号异常?分清两种波动
网络
承渊政道9 小时前
Linux网络学习【传输层协议UDP】
linux·网络·网络协议·学习·ubuntu·udp
小此方9 小时前
Linux网络(三十三):告别O(n)噩梦:从select/poll的挣扎到epoll红黑树+回调的降维打击,一文打通IO多路复用
linux·网络·驱动开发
2301_777998349 小时前
Linux 网络:数据链路层
linux·服务器·网络
国科安芯9 小时前
空间锂离子电池组管理系统CANFD通信网络的辐射可靠性设计
网络·信息与通信·canfd·电池·低轨卫星·抗辐射