From 03e737829ab8c57b965d82d16db663e681e67f3c Mon Sep 17 00:00:00 2001 From: Sergey Lyubka <valenok@gmail.com> Date: Thu, 5 Dec 2013 00:22:21 +0000 Subject: [PATCH] Made URI handler work --- build/src/core.c | 424 ++++++++++++++++++++++------------------------- build/src/core.h | 16 +- 2 files changed, 207 insertions(+), 233 deletions(-) diff --git a/build/src/core.c b/build/src/core.c index ebb45c649..5f102a883 100644 --- a/build/src/core.c +++ b/build/src/core.c @@ -66,6 +66,7 @@ typedef struct _stati64 file_stat_t; #define S_ISDIR(x) ((x) & _S_IFDIR) #define sleep(x) Sleep((x) * 1000) #define stat(x, y) _stati64((x), (y)) +#define to64(x) _atoi64(x) #ifndef va_copy #define va_copy(x,y) x = y #endif // MINGW #defines va_copy @@ -89,6 +90,7 @@ typedef struct stat file_stat_t; #define mutex_unlock(x) pthread_mutex_unlock(x) #define INVALID_SOCKET ((sock_t) -1) #define INT64_FMT PRId64 +#define to64(x) strtoll(x, NULL, 10) #endif //#include "mongoose.h" @@ -120,7 +122,7 @@ struct linked_list_link { struct linked_list_link *prev, *next; }; #endif #ifdef ENABLE_DBG -#define DBG(x) do { printf("%s::%s() ", __FILE__, __func__); \ +#define DBG(x) do { printf("%s::%s ", __FILE__, __func__); \ printf x; putchar('\n'); fflush(stdout); } while(0) #else #define DBG(x) @@ -195,8 +197,9 @@ struct iobuf { }; union endpoint { - int fd; // Opened regular local file - void *ssl; // SSL descriptor + int fd; // Opened regular local file + void *ssl; // SSL descriptor + struct uri_handler *uh; // URI handler user function }; enum endpoint_type { EP_NONE, EP_FILE, EP_USER }; @@ -207,17 +210,16 @@ struct connection { struct linked_list_link link; // Linkage to server->active_connections struct mg_server *server; sock_t client_sock; // Connected client - union socket_address csa; // Client's socket address struct iobuf local_iobuf; struct iobuf remote_iobuf; union endpoint endpoint; enum endpoint_type endpoint_type; time_t expire_time; char *path_info; - int request_len; - int flags; - int status_code; - mutex_t mutex; // Guards concurrent mg_write() calls + char *request; + int request_len; // Request length, including last \r\n after last header + int flags; // CONN_* flags: CONN_CLOSE, CONN_SPOOL_DONE, etc + mutex_t mutex; // Guards concurrent mg_write() calls }; static void close_local_endpoint(struct connection *conn); @@ -326,20 +328,6 @@ int mg_start_thread(void *(*f)(void *), void *p) { #endif } -#if 0 -static int call_user(int event_type, struct mg_connection *conn, void *p) { - if (conn != NULL && conn->server != NULL) { - conn->event.user_data = conn->server->user_data; - conn->event.type = event_type; - conn->event.event_param = p; - conn->event.request_info = &conn->request_info; - conn->event.conn = conn; - } - return !conn || !conn->server || !conn->server->event_handler ? 0 : - conn->server->event_handler(&conn->event); -} -#endif - static void set_close_on_exec(int fd) { #ifdef _WIN32 (void) SetHandleInformation((HANDLE) fd, HANDLE_FLAG_INHERIT, 0); @@ -565,29 +553,19 @@ static struct connection *accept_new_connection(struct mg_server *server) { sock_t sock = INVALID_SOCKET; struct connection *conn = NULL; + // NOTE(lsm): on Windows, sock is always > FD_SETSIZE if ((sock = accept(server->listening_sock, &sa.sa, &len)) == INVALID_SOCKET) { -#if 0 - } else if (sock >= FD_SETSIZE) { - DBG((">fd_setsize")); - closesocket(sock); -#endif } else if (!check_acl(server->config_options[ACCESS_CONTROL_LIST], ntohl(* (uint32_t *) &sa.sin.sin_addr))) { + // NOTE(lsm): check_acl doesn't work for IPv6 closesocket(sock); - } else if ((conn = (struct connection *) - calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) { + } else if ((conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) { closesocket(sock); } else { - // Put so socket structure into the queue set_close_on_exec(sock); set_non_blocking_mode(sock); conn->server = server; conn->client_sock = sock; - conn->csa = sa; - conn->local_iobuf.buf = (char *) conn + sizeof(*conn); - conn->local_iobuf.size = MAX_REQUEST_SIZE; - conn->remote_iobuf.buf = (char *) calloc(1, IOBUF_SIZE); - conn->remote_iobuf.size = IOBUF_SIZE; mutex_init(&conn->mutex); LINKED_LIST_ADD_TO_FRONT(&server->active_connections, &conn->link); DBG(("added conn %p", conn)); @@ -600,7 +578,9 @@ static void close_conn(struct connection *conn) { DBG(("closing %p", conn)); LINKED_LIST_REMOVE(&conn->link); closesocket(conn->client_sock); - free(conn->remote_iobuf.buf); + free(conn->request); // It's OK to free(NULL) + free(conn->remote_iobuf.buf); // It's OK to free(NULL) + free(conn->local_iobuf.buf); // It's OK to free(NULL) mutex_destroy(&conn->mutex); free(conn); } @@ -648,6 +628,50 @@ static char *skip(char **buf, const char *delimiters) { return begin_word; } +// Protect against directory disclosure attack by removing '..', +// excessive '/' and '\' characters +static void remove_double_dots_and_double_slashes(char *s) { + char *p = s; + + while (*s != '\0') { + *p++ = *s++; + if (s[-1] == '/' || s[-1] == '\\') { + // Skip all following slashes, backslashes and double-dots + while (s[0] != '\0') { + if (s[0] == '/' || s[0] == '\\') { s++; } + else if (s[0] == '.' && s[1] == '.') { s += 2; } + else { break; } + } + } + } + *p = '\0'; +} + +int mg_url_decode(const char *src, int src_len, char *dst, + int dst_len, int is_form_url_encoded) { + int i, j, a, b; +#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') + + for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { + if (src[i] == '%' && i < src_len - 2 && + isxdigit(* (const unsigned char *) (src + i + 1)) && + isxdigit(* (const unsigned char *) (src + i + 2))) { + a = tolower(* (const unsigned char *) (src + i + 1)); + b = tolower(* (const unsigned char *) (src + i + 2)); + dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b)); + i += 2; + } else if (is_form_url_encoded && src[i] == '+') { + dst[j] = ' '; + } else { + dst[j] = src[i]; + } + } + + dst[j] = '\0'; // Null-terminate the destination + + return i >= src_len ? j : -1; +} + // Parse HTTP headers from the given buffer, advance buffer to the point // where parsing stopped. static void parse_http_headers(char **buf, struct mg_connection *ri) { @@ -674,35 +698,42 @@ static int is_valid_http_method(const char *method) { // This function modifies the buffer by NUL-terminating // HTTP request components, header names and header values. static int parse_http_message(char *buf, int len, struct mg_connection *ri) { - int is_request, request_len = get_request_len((unsigned char *) buf, len); - if (request_len > 0) { - // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port - ri->request_method = ri->uri = ri->http_version = NULL; - ri->num_headers = 0; - buf[request_len - 1] = '\0'; - - // RFC says that all initial whitespaces should be ingored - while (*buf != '\0' && isspace(* (unsigned char *) buf)) { - buf++; + int is_request, n; + + // Reset attributes. DO NOT TOUCH remote_ip, remote_port + ri->request_method = ri->uri = ri->http_version = NULL; + ri->num_headers = 0; + buf[len - 1] = '\0'; + + // RFC says that all initial whitespaces should be ingored + while (*buf != '\0' && isspace(* (unsigned char *) buf)) { + buf++; + } + ri->request_method = skip(&buf, " "); + ri->uri = skip(&buf, " "); + ri->http_version = skip(&buf, "\r\n"); + + // HTTP message could be either HTTP request or HTTP response, e.g. + // "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." + is_request = is_valid_http_method(ri->request_method); + if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) || + (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) { + len = -1; + } else { + if (is_request) { + ri->http_version += 5; } - ri->request_method = skip(&buf, " "); - ri->uri = skip(&buf, " "); - ri->http_version = skip(&buf, "\r\n"); - - // HTTP message could be either HTTP request or HTTP response, e.g. - // "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." - is_request = is_valid_http_method(ri->request_method); - if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) || - (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) { - request_len = -1; - } else { - if (is_request) { - ri->http_version += 5; - } - parse_http_headers(&buf, ri); + parse_http_headers(&buf, ri); + + if ((ri->query_string = strchr(ri->uri, '?')) != NULL) { + *(char *) ri->query_string++ = '\0'; } + n = (int) strlen(ri->uri); + mg_url_decode(ri->uri, n, (char *) ri->uri, n + 1, 0); + remove_double_dots_and_double_slashes((char *) ri->uri); } - return request_len; + + return len; } static int lowercase(const char *s) { @@ -770,50 +801,6 @@ static int match_prefix(const char *pattern, int pattern_len, const char *str) { return j; } -// Protect against directory disclosure attack by removing '..', -// excessive '/' and '\' characters -static void remove_double_dots_and_double_slashes(char *s) { - char *p = s; - - while (*s != '\0') { - *p++ = *s++; - if (s[-1] == '/' || s[-1] == '\\') { - // Skip all following slashes, backslashes and double-dots - while (s[0] != '\0') { - if (s[0] == '/' || s[0] == '\\') { s++; } - else if (s[0] == '.' && s[1] == '.') { s += 2; } - else { break; } - } - } - } - *p = '\0'; -} - -int mg_url_decode(const char *src, int src_len, char *dst, - int dst_len, int is_form_url_encoded) { - int i, j, a, b; -#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') - - for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { - if (src[i] == '%' && i < src_len - 2 && - isxdigit(* (const unsigned char *) (src + i + 1)) && - isxdigit(* (const unsigned char *) (src + i + 2))) { - a = tolower(* (const unsigned char *) (src + i + 1)); - b = tolower(* (const unsigned char *) (src + i + 2)); - dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b)); - i += 2; - } else if (is_form_url_encoded && src[i] == '+') { - dst[j] = ' '; - } else { - dst[j] = src[i]; - } - } - - dst[j] = '\0'; // Null-terminate the destination - - return i >= src_len ? j : -1; -} - // Return HTTP header value, or NULL if not found. const char *mg_get_header(const struct mg_connection *ri, const char *s) { int i; @@ -867,67 +854,40 @@ static int convert_uri_to_file_name(struct connection *conn, char *buf, } static int spool(struct iobuf *io, const void *buf, int len) { + static const float mult = 1.2; char *p = NULL; - int new_len = io->len + len; + int new_len = 0; - DBG(("%d %d %d", len, io->len, io->size)); + assert(io->len >= 0); + assert(io->len <= io->size); + + //DBG(("1. %d %d %d", len, io->len, io->size)); if (len <= 0) { - } else if (new_len < io->size) { + } else if ((new_len = io->len + len) < io->size) { memcpy(io->buf + io->len, buf, len); - io->len += len; - } else if ((p = (char *) realloc(io->buf, new_len * 2)) != NULL) { + io->len = new_len; + } else if ((p = (char *) realloc(io->buf, new_len * mult)) != NULL) { io->buf = p; memcpy(io->buf + io->len, buf, len); io->len = new_len; - io->size = new_len * 2; - } else { - len = 0; - } - return len; -} - -static int vspool(struct iobuf *io, const char *fmt, va_list ap) { - char *ptr = io->buf; - va_list ap_copy; - int len; - - va_copy(ap_copy, ap); - len = vsnprintf(NULL, 0, fmt, ap_copy); - - if (len <= 0) { - } else if (len < io->size - io->len || - (ptr = (char *) realloc(io->buf, io->len + len + 1 - io->size)) - != NULL) { - io->buf = ptr; - vsnprintf(io->buf + io->len, len + 1, fmt, ap); - io->len += len; + io->size = new_len * mult; } else { len = 0; } + DBG(("%d %d %d", len, io->len, io->size)); return len; } -int mg_printf(struct mg_connection *c, const char *fmt, ...) { - struct connection *conn = (struct connection *) c; - va_list ap; - int ret; - va_start(ap, fmt); - mutex_lock(&conn->mutex); - ret = vspool(&conn->remote_iobuf, fmt, ap); - mutex_unlock(&conn->mutex); - va_end(ap); - send(conn->server->ctl[1], ".", 1, 0); // Wake up select call - return ret; -} - int mg_write(struct mg_connection *c, const void *buf, int len) { struct connection *conn = (struct connection *) c; int ret; + mutex_lock(&conn->mutex); ret = spool(&conn->remote_iobuf, buf, len); mutex_unlock(&conn->mutex); send(conn->server->ctl[1], ".", 1, 0); // Wake up select call + return ret; } @@ -1010,16 +970,15 @@ static void construct_etag(char *buf, size_t buf_len, const file_stat_t *st) { static void open_file_endpoint(struct connection *conn, const char *path, file_stat_t *st) { - char date[64], lm[64], etag[64], range[64]; + char date[64], lm[64], etag[64], range[64], headers[500]; const char *msg = "OK", *hdr; time_t curtime = time(NULL); int64_t cl, r1, r2; struct vec mime_vec; - int n; + int n, status_code = 200; conn->endpoint_type = EP_FILE; set_close_on_exec(conn->endpoint.fd); - conn->status_code = 200; get_mime_type(conn->server, path, &mime_vec); cl = st->st_size; @@ -1030,7 +989,7 @@ static void open_file_endpoint(struct connection *conn, const char *path, hdr = mg_get_header(&conn->mg_conn, "Range"); if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 && r1 >= 0 && r2 >= 0) { - conn->status_code = 206; + status_code = 206; cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1; snprintf(range, sizeof(range), "Content-Range: bytes " "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n", @@ -1045,18 +1004,19 @@ static void open_file_endpoint(struct connection *conn, const char *path, gmt_time_string(lm, sizeof(lm), &st->st_mtime); construct_etag(etag, sizeof(etag), st); - mg_printf(&conn->mg_conn, - "HTTP/1.1 %d %s\r\n" - "Date: %s\r\n" - "Last-Modified: %s\r\n" - "Etag: %s\r\n" - "Content-Type: %.*s\r\n" - "Content-Length: %" INT64_FMT "\r\n" - "Connection: %s\r\n" - "Accept-Ranges: bytes\r\n" - "%s%s\r\n", - conn->status_code, msg, date, lm, etag, (int) mime_vec.len, - mime_vec.ptr, cl, "keep-alive", range, EXTRA_HTTP_HEADERS); + n = snprintf(headers, sizeof(headers), + "HTTP/1.1 %d %s\r\n" + "Date: %s\r\n" + "Last-Modified: %s\r\n" + "Etag: %s\r\n" + "Content-Type: %.*s\r\n" + "Content-Length: %" INT64_FMT "\r\n" + "Connection: %s\r\n" + "Accept-Ranges: bytes\r\n" + "%s%s\r\n", + status_code, msg, date, lm, etag, (int) mime_vec.len, + mime_vec.ptr, cl, "keep-alive", range, EXTRA_HTTP_HEADERS); + spool(&conn->remote_iobuf, headers, n); if (!strcmp(conn->mg_conn.request_method, "HEAD")) { conn->flags |= CONN_SPOOL_DONE; @@ -1135,8 +1095,8 @@ static struct uri_handler *find_uri_handler(struct mg_server *server, // For given directory path, substitute it to valid index file. // Return 0 if index file has been found, -1 if not found. // If the file is found, it's stats is returned in stp. -static int substitute_index_file(struct connection *conn, char *path, - size_t path_len, file_stat_t *stp) { +static int find_index_file(struct connection *conn, char *path, + size_t path_len, file_stat_t *stp) { const char *list = conn->server->config_options[INDEX_FILES]; file_stat_t st; struct vec filename_vec; @@ -1179,33 +1139,40 @@ static int substitute_index_file(struct connection *conn, char *path, } static void send_http_error(struct connection *conn, const char *fmt, ...) { + char buf[500]; + int len; va_list ap; + va_start(ap, fmt); - vspool(&conn->remote_iobuf, fmt, ap); + len = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); + + spool(&conn->remote_iobuf, buf, len); conn->flags |= CONN_SPOOL_DONE; } -static void exec_lua_script(struct connection *conn, const char *path) { - send_http_error(conn, "%s", "HTTP/1.1 501 Not Implemented\r\n\r\n"); +static void call_uri_handler_if_data_is_buffered(struct connection *conn) { + if (conn->local_iobuf.len >= conn->mg_conn.content_len) { + conn->endpoint.uh->handler(&conn->mg_conn); + close_local_endpoint(conn); + } } static void open_local_endpoint(struct connection *conn) { char path[MAX_PATH_SIZE] = {'\0'}; file_stat_t st; - int uri_len, exists = 0, is_directory = 0; - struct uri_handler *uh; + int exists = 0, is_directory = 0; + const char *cl_hdr = mg_get_header(&conn->mg_conn, "Content-Length"); - if ((conn->mg_conn.query_string = strchr(conn->mg_conn.uri, '?')) != NULL) { - * ((char *) conn->mg_conn.query_string++) = '\0'; - } - uri_len = (int) strlen(conn->mg_conn.uri); - mg_url_decode(conn->mg_conn.uri, uri_len, (char *) conn->mg_conn.uri, - uri_len + 1, 0); - remove_double_dots_and_double_slashes((char *) conn->mg_conn.uri); + conn->mg_conn.content_len = cl_hdr == NULL ? 0 : to64(cl_hdr); - if ((uh = find_uri_handler(conn->server, conn->mg_conn.uri)) != NULL) { + // Call URI handler if one is registered for this URI + conn->endpoint.uh = find_uri_handler(conn->server, conn->mg_conn.uri); + if (conn->endpoint.uh != NULL) { conn->endpoint_type = EP_USER; + conn->mg_conn.content = conn->local_iobuf.buf; + call_uri_handler_if_data_is_buffered(conn); + return; } exists = convert_uri_to_file_name(conn, path, sizeof(path), &st); @@ -1213,14 +1180,10 @@ static void open_local_endpoint(struct connection *conn) { if (!exists) { send_http_error(conn, "%s", "HTTP/1.1 404 Not Found\r\n\r\n"); - } else if (is_directory && conn->mg_conn.uri[uri_len - 1] != '/') { - send_http_error(conn, "HTTP/1.1 301 Moved Permanently\r\n" - "Location: %s/\r\n\r\n", conn->mg_conn.uri); - } else if (is_directory && - !substitute_index_file(conn, path, sizeof(path), &st)) { + } else if (is_directory && !find_index_file(conn, path, sizeof(path), &st)) { send_http_error(conn, "%s", "HTTP/1.1 403 Listing Denied\r\n\r\n"); } else if (match_prefix(LUA_SCRIPT_PATTERN, 6, path) > 0) { - exec_lua_script(conn, path); + send_http_error(conn, "%s", "HTTP/1.1 501 Not Implemented\r\n\r\n"); conn->flags |= CONN_SPOOL_DONE; } else if (is_not_modified(conn, &st)) { send_http_error(conn, "%s", "HTTP/1.1 304 Not Modified\r\n\r\n"); @@ -1231,40 +1194,54 @@ static void open_local_endpoint(struct connection *conn) { } } -static int io_space(const struct iobuf *io) { - return io->size - io->len; +static void send_continue_if_expected(struct connection *conn) { + static const char expect_response[] = "HTTP/1.1 100 Continue\r\n\r\n"; + const char *expect_hdr = mg_get_header(&conn->mg_conn, "Expect"); + + if (expect_hdr != NULL) { + spool(&conn->remote_iobuf, expect_response, sizeof(expect_response) - 1); + } } static void process_request(struct connection *conn) { struct iobuf *io = &conn->local_iobuf; //DBG(("parse_http_message(%d [%.*s])", io->len, io->len, io->buf)); - if (conn->request_len == 0) { - conn->request_len = parse_http_message(io->buf, io->len, &conn->mg_conn); + if (conn->request_len == 0 && + (conn->request_len = get_request_len((unsigned char *) io->buf, + io->len)) > 0) { + // If request is buffered in, remove it from the iobuf. This is because + // iobuf could be reallocated, and pointers in parsed request could + // become ivalid. + conn->request = (char *) malloc(conn->request_len); + memcpy(conn->request, io->buf, conn->request_len); + memmove(io->buf, io->buf + conn->request_len, io->len - conn->request_len); + io->len -= conn->request_len; + conn->request_len = parse_http_message(conn->request, conn->request_len, + &conn->mg_conn); + DBG(("request_len = %d", conn->request_len)); } - DBG(("parse_http_message() -> %d", conn->request_len)); if (conn->request_len < 0 || - (conn->request_len == 0 && io_space(io) <= 0)) { + (conn->request_len == 0 && io->len > MAX_REQUEST_SIZE)) { // Invalid request, or request is too big: close the connection conn->flags |= CONN_CLOSE; } else if (conn->request_len > 0 && conn->endpoint_type == EP_NONE) { + send_continue_if_expected(conn); open_local_endpoint(conn); + } else if (conn->endpoint_type == EP_USER) { + call_uri_handler_if_data_is_buffered(conn); } } static void read_from_client(struct connection *conn) { - struct iobuf *io = &conn->local_iobuf; - int n = recv(conn->client_sock, io->buf + io->len, io->size - io->len, 0); - - //DBG(("Read: %d [%.*s]", n, n, io->buf + io->len)); - assert(io->len >= 0); - assert(io->len <= io->size); + char buf[IOBUF_SIZE]; + int n = recv(conn->client_sock, buf, sizeof(buf), 0); if (is_error(n)) { conn->flags |= CONN_CLOSE; } else if (n > 0) { - io->len += n; + spool(&conn->local_iobuf, buf, n); process_request(conn); } } @@ -1279,22 +1256,22 @@ static int should_keep_alive(const struct connection *conn) { } static void close_local_endpoint(struct connection *conn) { - struct iobuf *io = &conn->local_iobuf; - int keep_alive = should_keep_alive(conn); // Must be done before memmove + int keep_alive = should_keep_alive(conn); // Must be done before free() + + //DBG(("Closing for conn %p", conn)); // Close file descriptor switch (conn->endpoint_type) { case EP_FILE: close(conn->endpoint.fd); break; + case EP_USER: break; case EP_NONE: break; default: assert(0); break; } - // Get rid of that request from the buffer. NOTE: order is important here - assert(conn->request_len <= io->len); - memmove(io->buf, io->buf + conn->request_len, io->len - conn->request_len); - io->len -= conn->request_len; conn->endpoint_type = EP_NONE; conn->request_len = 0; + free(conn->request); + conn->request = NULL; if (keep_alive) { process_request(conn); // Can call us recursively if pipelining is used @@ -1304,16 +1281,13 @@ static void close_local_endpoint(struct connection *conn) { } static void transfer_file_data(struct connection *conn) { - struct iobuf *io = &conn->remote_iobuf; - int n, rem_space = io_space(io); - - if (rem_space <= 0) return; - n = read(conn->endpoint.fd, io->buf + io->len, rem_space); + char buf[IOBUF_SIZE]; + int n = read(conn->endpoint.fd, buf, sizeof(buf)); if (is_error(n)) { close_local_endpoint(conn); } else if (n > 0) { - io->len += n; + spool(&conn->remote_iobuf, buf, n); } } @@ -1488,22 +1462,6 @@ struct mg_server *mg_create_server(void *server_data) { server->server_data = server_data; server->listening_sock = INVALID_SOCKET; -#if 0 - while (opts != NULL && (name = *opts++) != NULL) { - if ((i = get_option_index(name)) == -1) { - snprintf(error_msg, sizeof(error_msg), "Invalid option: [%s]", name); - } else if ((value = *opts++) == NULL) { - snprintf(error_msg, sizeof(error_msg), "[%s] cannot be NULL", name); - } else { - if (server->config_options[i] != NULL) { - free(server->config_options[i]); - } - server->config_options[i] = mg_strdup(value); - DBG(("[%s] -> [%s]", name, value)); - } - } -#endif - // Set default options values for (i = 0; static_config_options[i * 2] != NULL; i++) { value = static_config_options[i * 2 + 1]; @@ -1518,7 +1476,9 @@ struct mg_server *mg_create_server(void *server_data) { // End of library, start of the application code static void iterate_callback(struct mg_connection *c, void *param) { - mg_write(c, "%d", * (int *) param); + if (c->connection_param != NULL) { + mg_write(c, "%d", * (int *) param); + } } static void *timer_thread(void *param) { @@ -1534,7 +1494,17 @@ static void *timer_thread(void *param) { } static int websocket_handler(struct mg_connection *conn) { - mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n\r\n:-)\n"); + char headers[500], content[500]; + int headers_len, content_len; + + content_len = snprintf(content, sizeof(content), "%s %s, POST len %d\n", + conn->request_method, conn->uri, conn->content_len); + headers_len = snprintf(headers, sizeof(headers), "HTTP/1.0 200 OK\r\n" + "Content-Length: %d\r\n\r\n", content_len); + + mg_write(conn, headers, headers_len); + mg_write(conn, content, content_len); + return 1; } @@ -1549,7 +1519,7 @@ int main(void) { printf("Started on port %s\n", mg_get_option(server, "listening_port")); for (;;) { - mg_poll_server(server, 1000); + mg_poll_server(server, 3000); } mg_destroy_server(&server); diff --git a/build/src/core.h b/build/src/core.h index f3fc54255..d6695796c 100644 --- a/build/src/core.h +++ b/build/src/core.h @@ -33,15 +33,19 @@ struct mg_connection { const char *uri; // URL-decoded URI const char *http_version; // E.g. "1.0", "1.1" const char *query_string; // URL part after '?', not including '?', or NULL + long remote_ip; // Client's IP address int remote_port; // Client's port - int is_ssl; // 1 if SSL-ed, 0 if not + int num_headers; // Number of HTTP headers struct mg_header { const char *name; // HTTP header name const char *value; // HTTP header value } http_headers[64]; // Maximum 64 headers + char *content; // POST (or websocket message) data, or NULL + int content_len; // content length + void *server_param; // Parameter passed to mg_add_uri_handler() void *connection_param; // Placeholder for connection-specific data }; @@ -64,16 +68,16 @@ const char **mg_get_valid_option_names(void); const char *mg_get_option(const struct mg_server *server, const char *name); // Websocket functions -void mg_websocket_handshake(struct mg_connection *); -int mg_websocket_read(struct mg_connection *, int *bits, char **data); -int mg_websocket_write(struct mg_connection* conn, int opcode, - const char *data, size_t data_len); +//void mg_websocket_handshake(struct mg_connection *); +//int mg_websocket_read(struct mg_connection *, int *bits, char **data); +//int mg_websocket_write(struct mg_connection* conn, int opcode, +// const char *data, size_t data_len); // Connection management functions int mg_write(struct mg_connection *, const void *buf, int len); -int mg_printf(struct mg_connection *, const char *fmt, ...); #if 0 +int mg_printf(struct mg_connection *, const char *fmt, ...); void mg_send_file(struct mg_connection *, const char *path); int mg_read(struct mg_connection *, void *buf, int len); const char *mg_get_header(const struct mg_connection *, const char *name); -- GitLab