|
@@ -10585,407 +10585,406 @@ deprecated_websocket_data_wrapper(struct mg_connection *conn,
|
|
static void
|
|
static void
|
|
handle_request(struct mg_connection *conn)
|
|
handle_request(struct mg_connection *conn)
|
|
{
|
|
{
|
|
- if (conn) {
|
|
|
|
- struct mg_request_info *ri = &conn->request_info;
|
|
|
|
- char path[PATH_MAX];
|
|
|
|
- int uri_len, ssl_index;
|
|
|
|
- int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
|
|
|
|
- is_put_or_delete_request = 0, is_callback_resource = 0;
|
|
|
|
- int i;
|
|
|
|
- struct mg_file file = STRUCT_FILE_INITIALIZER;
|
|
|
|
- mg_request_handler callback_handler = NULL;
|
|
|
|
- struct mg_websocket_subprotocols *subprotocols;
|
|
|
|
- mg_websocket_connect_handler ws_connect_handler = NULL;
|
|
|
|
- mg_websocket_ready_handler ws_ready_handler = NULL;
|
|
|
|
- mg_websocket_data_handler ws_data_handler = NULL;
|
|
|
|
- mg_websocket_close_handler ws_close_handler = NULL;
|
|
|
|
- void *callback_data = NULL;
|
|
|
|
- mg_authorization_handler auth_handler = NULL;
|
|
|
|
- void *auth_callback_data = NULL;
|
|
|
|
|
|
+ struct mg_request_info *ri = &conn->request_info;
|
|
|
|
+ char path[PATH_MAX];
|
|
|
|
+ int uri_len, ssl_index;
|
|
|
|
+ int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
|
|
|
|
+ is_put_or_delete_request = 0, is_callback_resource = 0;
|
|
|
|
+ int i;
|
|
|
|
+ struct mg_file file = STRUCT_FILE_INITIALIZER;
|
|
|
|
+ mg_request_handler callback_handler = NULL;
|
|
|
|
+ struct mg_websocket_subprotocols *subprotocols;
|
|
|
|
+ mg_websocket_connect_handler ws_connect_handler = NULL;
|
|
|
|
+ mg_websocket_ready_handler ws_ready_handler = NULL;
|
|
|
|
+ mg_websocket_data_handler ws_data_handler = NULL;
|
|
|
|
+ mg_websocket_close_handler ws_close_handler = NULL;
|
|
|
|
+ void *callback_data = NULL;
|
|
|
|
+ mg_authorization_handler auth_handler = NULL;
|
|
|
|
+ void *auth_callback_data = NULL;
|
|
#if !defined(NO_FILES)
|
|
#if !defined(NO_FILES)
|
|
- time_t curtime = time(NULL);
|
|
|
|
- char date[64];
|
|
|
|
|
|
+ time_t curtime = time(NULL);
|
|
|
|
+ char date[64];
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- path[0] = 0;
|
|
|
|
|
|
+ path[0] = 0;
|
|
|
|
|
|
- if (!ri) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!ri) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- /* 1. get the request url */
|
|
|
|
- /* 1.1. split into url and query string */
|
|
|
|
- if ((conn->request_info.query_string = strchr(ri->request_uri, '?'))
|
|
|
|
- != NULL) {
|
|
|
|
- *((char *)conn->request_info.query_string++) = '\0';
|
|
|
|
- }
|
|
|
|
|
|
+ /* 1. get the request url */
|
|
|
|
+ /* 1.1. split into url and query string */
|
|
|
|
+ if ((conn->request_info.query_string = strchr(ri->request_uri, '?'))
|
|
|
|
+ != NULL) {
|
|
|
|
+ *((char *)conn->request_info.query_string++) = '\0';
|
|
|
|
+ }
|
|
|
|
|
|
- /* 1.2. do a https redirect, if required. Do not decode URIs yet. */
|
|
|
|
- if (!conn->client.is_ssl && conn->client.ssl_redir) {
|
|
|
|
- ssl_index = get_first_ssl_listener_index(conn->ctx);
|
|
|
|
- if (ssl_index >= 0) {
|
|
|
|
- redirect_to_https_port(conn, ssl_index);
|
|
|
|
- } else {
|
|
|
|
- /* A http to https forward port has been specified,
|
|
|
|
- * but no https port to forward to. */
|
|
|
|
- send_http_error(conn,
|
|
|
|
- 503,
|
|
|
|
- "%s",
|
|
|
|
- "Error: SSL forward not configured properly");
|
|
|
|
- mg_cry(conn, "Can not redirect to SSL, no SSL port available");
|
|
|
|
- }
|
|
|
|
- return;
|
|
|
|
|
|
+ /* 1.2. do a https redirect, if required. Do not decode URIs yet. */
|
|
|
|
+ if (!conn->client.is_ssl && conn->client.ssl_redir) {
|
|
|
|
+ ssl_index = get_first_ssl_listener_index(conn->ctx);
|
|
|
|
+ if (ssl_index >= 0) {
|
|
|
|
+ redirect_to_https_port(conn, ssl_index);
|
|
|
|
+ } else {
|
|
|
|
+ /* A http to https forward port has been specified,
|
|
|
|
+ * but no https port to forward to. */
|
|
|
|
+ send_http_error(conn,
|
|
|
|
+ 503,
|
|
|
|
+ "%s",
|
|
|
|
+ "Error: SSL forward not configured properly");
|
|
|
|
+ mg_cry(conn, "Can not redirect to SSL, no SSL port available");
|
|
}
|
|
}
|
|
- uri_len = (int)strlen(ri->local_uri);
|
|
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ uri_len = (int)strlen(ri->local_uri);
|
|
|
|
|
|
- /* 1.3. decode url (if config says so) */
|
|
|
|
- if (should_decode_url(conn)) {
|
|
|
|
- mg_url_decode(
|
|
|
|
- ri->local_uri, uri_len, (char *)ri->local_uri, uri_len + 1, 0);
|
|
|
|
- }
|
|
|
|
|
|
+ /* 1.3. decode url (if config says so) */
|
|
|
|
+ if (should_decode_url(conn)) {
|
|
|
|
+ mg_url_decode(
|
|
|
|
+ ri->local_uri, uri_len, (char *)ri->local_uri, uri_len + 1, 0);
|
|
|
|
+ }
|
|
|
|
|
|
- /* 1.4. clean URIs, so a path like allowed_dir/../forbidden_file is
|
|
|
|
- * not possible */
|
|
|
|
- remove_double_dots_and_double_slashes((char *)ri->local_uri);
|
|
|
|
|
|
+ /* 1.4. clean URIs, so a path like allowed_dir/../forbidden_file is
|
|
|
|
+ * not possible */
|
|
|
|
+ remove_double_dots_and_double_slashes((char *)ri->local_uri);
|
|
|
|
|
|
- /* step 1. completed, the url is known now */
|
|
|
|
- uri_len = (int)strlen(ri->local_uri);
|
|
|
|
- DEBUG_TRACE("URL: %s", ri->local_uri);
|
|
|
|
|
|
+ /* step 1. completed, the url is known now */
|
|
|
|
+ uri_len = (int)strlen(ri->local_uri);
|
|
|
|
+ DEBUG_TRACE("URL: %s", ri->local_uri);
|
|
|
|
|
|
- /* 3. if this ip has limited speed, set it for this connection */
|
|
|
|
- conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
|
|
|
|
- get_remote_ip(conn),
|
|
|
|
- ri->local_uri);
|
|
|
|
|
|
+ /* 3. if this ip has limited speed, set it for this connection */
|
|
|
|
+ conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
|
|
|
|
+ get_remote_ip(conn),
|
|
|
|
+ ri->local_uri);
|
|
|
|
|
|
- /* 4. call a "handle everything" callback, if registered */
|
|
|
|
- if (conn->ctx->callbacks.begin_request != NULL) {
|
|
|
|
- /* Note that since V1.7 the "begin_request" function is called
|
|
|
|
- * before an authorization check. If an authorization check is
|
|
|
|
- * required, use a request_handler instead. */
|
|
|
|
- i = conn->ctx->callbacks.begin_request(conn);
|
|
|
|
- if (i > 0) {
|
|
|
|
- /* callback already processed the request. Store the
|
|
|
|
- return value as a status code for the access log. */
|
|
|
|
- conn->status_code = i;
|
|
|
|
- discard_unread_request_data(conn);
|
|
|
|
- return;
|
|
|
|
- } else if (i == 0) {
|
|
|
|
- /* civetweb should process the request */
|
|
|
|
- } else {
|
|
|
|
- /* unspecified - may change with the next version */
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ /* 4. call a "handle everything" callback, if registered */
|
|
|
|
+ if (conn->ctx->callbacks.begin_request != NULL) {
|
|
|
|
+ /* Note that since V1.7 the "begin_request" function is called
|
|
|
|
+ * before an authorization check. If an authorization check is
|
|
|
|
+ * required, use a request_handler instead. */
|
|
|
|
+ i = conn->ctx->callbacks.begin_request(conn);
|
|
|
|
+ if (i > 0) {
|
|
|
|
+ /* callback already processed the request. Store the
|
|
|
|
+ return value as a status code for the access log. */
|
|
|
|
+ conn->status_code = i;
|
|
|
|
+ discard_unread_request_data(conn);
|
|
|
|
+ return;
|
|
|
|
+ } else if (i == 0) {
|
|
|
|
+ /* civetweb should process the request */
|
|
|
|
+ } else {
|
|
|
|
+ /* unspecified - may change with the next version */
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- /* request not yet handled by a handler or redirect, so the request
|
|
|
|
- * is processed here */
|
|
|
|
|
|
+ /* request not yet handled by a handler or redirect, so the request
|
|
|
|
+ * is processed here */
|
|
|
|
|
|
- /* 5. interpret the url to find out how the request must be handled
|
|
|
|
- */
|
|
|
|
- /* 5.1. first test, if the request targets the regular http(s)://
|
|
|
|
- * protocol namespace or the websocket ws(s):// protocol namespace.
|
|
|
|
- */
|
|
|
|
- is_websocket_request = is_websocket_protocol(conn);
|
|
|
|
-
|
|
|
|
- /* 5.2. check if the request will be handled by a callback */
|
|
|
|
- if (get_request_handler(conn,
|
|
|
|
- is_websocket_request ? WEBSOCKET_HANDLER
|
|
|
|
- : REQUEST_HANDLER,
|
|
|
|
- &callback_handler,
|
|
|
|
- &subprotocols,
|
|
|
|
- &ws_connect_handler,
|
|
|
|
- &ws_ready_handler,
|
|
|
|
- &ws_data_handler,
|
|
|
|
- &ws_close_handler,
|
|
|
|
- NULL,
|
|
|
|
- &callback_data)) {
|
|
|
|
- /* 5.2.1. A callback will handle this request. All requests
|
|
|
|
- * handled
|
|
|
|
- * by a callback have to be considered as requests to a script
|
|
|
|
- * resource. */
|
|
|
|
- is_callback_resource = 1;
|
|
|
|
- is_script_resource = 1;
|
|
|
|
- is_put_or_delete_request = is_put_or_delete_method(conn);
|
|
|
|
- } else {
|
|
|
|
- no_callback_resource:
|
|
|
|
- /* 5.2.2. No callback is responsible for this request. The URI
|
|
|
|
- * addresses a file based resource (static content or Lua/cgi
|
|
|
|
- * scripts in the file system). */
|
|
|
|
- is_callback_resource = 0;
|
|
|
|
- interpret_uri(conn,
|
|
|
|
- path,
|
|
|
|
- sizeof(path),
|
|
|
|
- &file.stat,
|
|
|
|
- &is_found,
|
|
|
|
- &is_script_resource,
|
|
|
|
- &is_websocket_request,
|
|
|
|
- &is_put_or_delete_request);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* 6. authorization check */
|
|
|
|
- /* 6.1. a custom authorization handler is installed */
|
|
|
|
- if (get_request_handler(conn,
|
|
|
|
- AUTH_HANDLER,
|
|
|
|
- NULL,
|
|
|
|
- NULL,
|
|
|
|
- NULL,
|
|
|
|
- NULL,
|
|
|
|
- NULL,
|
|
|
|
- NULL,
|
|
|
|
- &auth_handler,
|
|
|
|
- &auth_callback_data)) {
|
|
|
|
- if (!auth_handler(conn, auth_callback_data)) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- } else if (is_put_or_delete_request && !is_script_resource
|
|
|
|
- && !is_callback_resource) {
|
|
|
|
|
|
+ /* 5. interpret the url to find out how the request must be handled
|
|
|
|
+ */
|
|
|
|
+ /* 5.1. first test, if the request targets the regular http(s)://
|
|
|
|
+ * protocol namespace or the websocket ws(s):// protocol namespace.
|
|
|
|
+ */
|
|
|
|
+ is_websocket_request = is_websocket_protocol(conn);
|
|
|
|
+
|
|
|
|
+ /* 5.2. check if the request will be handled by a callback */
|
|
|
|
+ if (get_request_handler(conn,
|
|
|
|
+ is_websocket_request ? WEBSOCKET_HANDLER
|
|
|
|
+ : REQUEST_HANDLER,
|
|
|
|
+ &callback_handler,
|
|
|
|
+ &subprotocols,
|
|
|
|
+ &ws_connect_handler,
|
|
|
|
+ &ws_ready_handler,
|
|
|
|
+ &ws_data_handler,
|
|
|
|
+ &ws_close_handler,
|
|
|
|
+ NULL,
|
|
|
|
+ &callback_data)) {
|
|
|
|
+ /* 5.2.1. A callback will handle this request. All requests
|
|
|
|
+ * handled
|
|
|
|
+ * by a callback have to be considered as requests to a script
|
|
|
|
+ * resource. */
|
|
|
|
+ is_callback_resource = 1;
|
|
|
|
+ is_script_resource = 1;
|
|
|
|
+ is_put_or_delete_request = is_put_or_delete_method(conn);
|
|
|
|
+ } else {
|
|
|
|
+ no_callback_resource:
|
|
|
|
+ /* 5.2.2. No callback is responsible for this request. The URI
|
|
|
|
+ * addresses a file based resource (static content or Lua/cgi
|
|
|
|
+ * scripts in the file system). */
|
|
|
|
+ is_callback_resource = 0;
|
|
|
|
+ interpret_uri(conn,
|
|
|
|
+ path,
|
|
|
|
+ sizeof(path),
|
|
|
|
+ &file.stat,
|
|
|
|
+ &is_found,
|
|
|
|
+ &is_script_resource,
|
|
|
|
+ &is_websocket_request,
|
|
|
|
+ &is_put_or_delete_request);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* 6. authorization check */
|
|
|
|
+ /* 6.1. a custom authorization handler is installed */
|
|
|
|
+ if (get_request_handler(conn,
|
|
|
|
+ AUTH_HANDLER,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL,
|
|
|
|
+ &auth_handler,
|
|
|
|
+ &auth_callback_data)) {
|
|
|
|
+ if (!auth_handler(conn, auth_callback_data)) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ } else if (is_put_or_delete_request && !is_script_resource
|
|
|
|
+ && !is_callback_resource) {
|
|
/* 6.2. this request is a PUT/DELETE to a real file */
|
|
/* 6.2. this request is a PUT/DELETE to a real file */
|
|
/* 6.2.1. thus, the server must have real files */
|
|
/* 6.2.1. thus, the server must have real files */
|
|
#if defined(NO_FILES)
|
|
#if defined(NO_FILES)
|
|
- if (1) {
|
|
|
|
|
|
+ if (1) {
|
|
#else
|
|
#else
|
|
- if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
|
|
|
|
|
|
+ if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
|
|
#endif
|
|
#endif
|
|
- /* This server does not have any real files, thus the
|
|
|
|
- * PUT/DELETE methods are not valid. */
|
|
|
|
- send_http_error(conn,
|
|
|
|
- 405,
|
|
|
|
- "%s method not allowed",
|
|
|
|
- conn->request_info.request_method);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ /* This server does not have any real files, thus the
|
|
|
|
+ * PUT/DELETE methods are not valid. */
|
|
|
|
+ send_http_error(conn,
|
|
|
|
+ 405,
|
|
|
|
+ "%s method not allowed",
|
|
|
|
+ conn->request_info.request_method);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
#if !defined(NO_FILES)
|
|
#if !defined(NO_FILES)
|
|
- /* 6.2.2. Check if put authorization for static files is
|
|
|
|
- * available.
|
|
|
|
- */
|
|
|
|
- if (!is_authorized_for_put(conn)) {
|
|
|
|
- send_authorization_request(conn);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ /* 6.2.2. Check if put authorization for static files is
|
|
|
|
+ * available.
|
|
|
|
+ */
|
|
|
|
+ if (!is_authorized_for_put(conn)) {
|
|
|
|
+ send_authorization_request(conn);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- } else {
|
|
|
|
- /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
|
|
|
|
- * or it is a PUT or DELETE request to a resource that does not
|
|
|
|
- * correspond to a file. Check authorization. */
|
|
|
|
- if (!check_authorization(conn, path)) {
|
|
|
|
- send_authorization_request(conn);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ } else {
|
|
|
|
+ /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
|
|
|
|
+ * or it is a PUT or DELETE request to a resource that does not
|
|
|
|
+ * correspond to a file. Check authorization. */
|
|
|
|
+ if (!check_authorization(conn, path)) {
|
|
|
|
+ send_authorization_request(conn);
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- /* request is authorized or does not need authorization */
|
|
|
|
|
|
+ /* request is authorized or does not need authorization */
|
|
|
|
|
|
- /* 7. check if there are request handlers for this uri */
|
|
|
|
- if (is_callback_resource) {
|
|
|
|
- if (!is_websocket_request) {
|
|
|
|
- i = callback_handler(conn, callback_data);
|
|
|
|
- if (i > 0) {
|
|
|
|
- /* Do nothing, callback has served the request. Store
|
|
|
|
- * the
|
|
|
|
- * return value as status code for the log and discard
|
|
|
|
- * all
|
|
|
|
- * data from the client not used by the callback. */
|
|
|
|
- conn->status_code = i;
|
|
|
|
- discard_unread_request_data(conn);
|
|
|
|
- } else {
|
|
|
|
- /* TODO (high): what if the handler did NOT handle the
|
|
|
|
- * request */
|
|
|
|
- /* The last version did handle this as a file request,
|
|
|
|
- * but
|
|
|
|
- * since a file request is not always a script resource,
|
|
|
|
- * the authorization check might be different */
|
|
|
|
- interpret_uri(conn,
|
|
|
|
- path,
|
|
|
|
- sizeof(path),
|
|
|
|
- &file.stat,
|
|
|
|
- &is_found,
|
|
|
|
- &is_script_resource,
|
|
|
|
- &is_websocket_request,
|
|
|
|
- &is_put_or_delete_request);
|
|
|
|
- callback_handler = NULL;
|
|
|
|
-
|
|
|
|
- /* Here we are at a dead end:
|
|
|
|
- * According to URI matching, a callback should be
|
|
|
|
- * responsible for handling the request,
|
|
|
|
- * we called it, but the callback declared itself
|
|
|
|
- * not responsible.
|
|
|
|
- * We use a goto here, to get out of this dead end,
|
|
|
|
- * and continue with the default handling.
|
|
|
|
- * A goto here is simpler and better to understand
|
|
|
|
- * than some curious loop. */
|
|
|
|
- goto no_callback_resource;
|
|
|
|
- }
|
|
|
|
|
|
+ /* 7. check if there are request handlers for this uri */
|
|
|
|
+ if (is_callback_resource) {
|
|
|
|
+ if (!is_websocket_request) {
|
|
|
|
+ i = callback_handler(conn, callback_data);
|
|
|
|
+ if (i > 0) {
|
|
|
|
+ /* Do nothing, callback has served the request. Store
|
|
|
|
+ * the
|
|
|
|
+ * return value as status code for the log and discard
|
|
|
|
+ * all
|
|
|
|
+ * data from the client not used by the callback. */
|
|
|
|
+ conn->status_code = i;
|
|
|
|
+ discard_unread_request_data(conn);
|
|
} else {
|
|
} else {
|
|
|
|
+ /* TODO (high): what if the handler did NOT handle the
|
|
|
|
+ * request */
|
|
|
|
+ /* The last version did handle this as a file request,
|
|
|
|
+ * but
|
|
|
|
+ * since a file request is not always a script resource,
|
|
|
|
+ * the authorization check might be different */
|
|
|
|
+ interpret_uri(conn,
|
|
|
|
+ path,
|
|
|
|
+ sizeof(path),
|
|
|
|
+ &file.stat,
|
|
|
|
+ &is_found,
|
|
|
|
+ &is_script_resource,
|
|
|
|
+ &is_websocket_request,
|
|
|
|
+ &is_put_or_delete_request);
|
|
|
|
+ callback_handler = NULL;
|
|
|
|
+
|
|
|
|
+ /* Here we are at a dead end:
|
|
|
|
+ * According to URI matching, a callback should be
|
|
|
|
+ * responsible for handling the request,
|
|
|
|
+ * we called it, but the callback declared itself
|
|
|
|
+ * not responsible.
|
|
|
|
+ * We use a goto here, to get out of this dead end,
|
|
|
|
+ * and continue with the default handling.
|
|
|
|
+ * A goto here is simpler and better to understand
|
|
|
|
+ * than some curious loop. */
|
|
|
|
+ goto no_callback_resource;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
#if defined(USE_WEBSOCKET)
|
|
#if defined(USE_WEBSOCKET)
|
|
- handle_websocket_request(conn,
|
|
|
|
- path,
|
|
|
|
- is_callback_resource,
|
|
|
|
- subprotocols,
|
|
|
|
- ws_connect_handler,
|
|
|
|
- ws_ready_handler,
|
|
|
|
- ws_data_handler,
|
|
|
|
- ws_close_handler,
|
|
|
|
- callback_data);
|
|
|
|
|
|
+ handle_websocket_request(conn,
|
|
|
|
+ path,
|
|
|
|
+ is_callback_resource,
|
|
|
|
+ subprotocols,
|
|
|
|
+ ws_connect_handler,
|
|
|
|
+ ws_ready_handler,
|
|
|
|
+ ws_data_handler,
|
|
|
|
+ ws_close_handler,
|
|
|
|
+ callback_data);
|
|
#endif
|
|
#endif
|
|
- }
|
|
|
|
- return;
|
|
|
|
}
|
|
}
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
/* 8. handle websocket requests */
|
|
/* 8. handle websocket requests */
|
|
#if defined(USE_WEBSOCKET)
|
|
#if defined(USE_WEBSOCKET)
|
|
- if (is_websocket_request) {
|
|
|
|
- if (is_script_resource) {
|
|
|
|
- /* Websocket Lua script */
|
|
|
|
- handle_websocket_request(conn,
|
|
|
|
- path,
|
|
|
|
- 0 /* Lua Script */,
|
|
|
|
- NULL,
|
|
|
|
- NULL,
|
|
|
|
- NULL,
|
|
|
|
- NULL,
|
|
|
|
- NULL,
|
|
|
|
- &conn->ctx->callbacks);
|
|
|
|
- } else {
|
|
|
|
|
|
+ if (is_websocket_request) {
|
|
|
|
+ if (is_script_resource) {
|
|
|
|
+ /* Websocket Lua script */
|
|
|
|
+ handle_websocket_request(conn,
|
|
|
|
+ path,
|
|
|
|
+ 0 /* Lua Script */,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL,
|
|
|
|
+ &conn->ctx->callbacks);
|
|
|
|
+ } else {
|
|
#if defined(MG_LEGACY_INTERFACE)
|
|
#if defined(MG_LEGACY_INTERFACE)
|
|
- handle_websocket_request(
|
|
|
|
- conn,
|
|
|
|
- path,
|
|
|
|
- !is_script_resource /* could be deprecated global callback */,
|
|
|
|
- NULL,
|
|
|
|
- deprecated_websocket_connect_wrapper,
|
|
|
|
- deprecated_websocket_ready_wrapper,
|
|
|
|
- deprecated_websocket_data_wrapper,
|
|
|
|
- NULL,
|
|
|
|
- &conn->ctx->callbacks);
|
|
|
|
|
|
+ handle_websocket_request(
|
|
|
|
+ conn,
|
|
|
|
+ path,
|
|
|
|
+ !is_script_resource /* could be deprecated global callback */,
|
|
|
|
+ NULL,
|
|
|
|
+ deprecated_websocket_connect_wrapper,
|
|
|
|
+ deprecated_websocket_ready_wrapper,
|
|
|
|
+ deprecated_websocket_data_wrapper,
|
|
|
|
+ NULL,
|
|
|
|
+ &conn->ctx->callbacks);
|
|
#else
|
|
#else
|
|
- send_http_error(conn, 404, "%s", "Not found");
|
|
|
|
|
|
+ send_http_error(conn, 404, "%s", "Not found");
|
|
#endif
|
|
#endif
|
|
- }
|
|
|
|
- return;
|
|
|
|
- } else
|
|
|
|
|
|
+ }
|
|
|
|
+ return;
|
|
|
|
+ } else
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(NO_FILES)
|
|
#if defined(NO_FILES)
|
|
- /* 9a. In case the server uses only callbacks, this uri is
|
|
|
|
- * unknown.
|
|
|
|
- * Then, all request handling ends here. */
|
|
|
|
- send_http_error(conn, 404, "%s", "Not Found");
|
|
|
|
|
|
+ /* 9a. In case the server uses only callbacks, this uri is
|
|
|
|
+ * unknown.
|
|
|
|
+ * Then, all request handling ends here. */
|
|
|
|
+ send_http_error(conn, 404, "%s", "Not Found");
|
|
|
|
|
|
#else
|
|
#else
|
|
- /* 9b. This request is either for a static file or resource handled
|
|
|
|
- * by a script file. Thus, a DOCUMENT_ROOT must exist. */
|
|
|
|
- if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
|
|
|
|
- send_http_error(conn, 404, "%s", "Not Found");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ /* 9b. This request is either for a static file or resource handled
|
|
|
|
+ * by a script file. Thus, a DOCUMENT_ROOT must exist. */
|
|
|
|
+ if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
|
|
|
|
+ send_http_error(conn, 404, "%s", "Not Found");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- /* 10. File is handled by a script. */
|
|
|
|
- if (is_script_resource) {
|
|
|
|
- handle_file_based_request(conn, path, &file);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ /* 10. File is handled by a script. */
|
|
|
|
+ if (is_script_resource) {
|
|
|
|
+ handle_file_based_request(conn, path, &file);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- /* 11. Handle put/delete/mkcol requests */
|
|
|
|
- if (is_put_or_delete_request) {
|
|
|
|
- /* 11.1. PUT method */
|
|
|
|
- if (!strcmp(ri->request_method, "PUT")) {
|
|
|
|
- put_file(conn, path);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- /* 11.2. DELETE method */
|
|
|
|
- if (!strcmp(ri->request_method, "DELETE")) {
|
|
|
|
- delete_file(conn, path);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- /* 11.3. MKCOL method */
|
|
|
|
- if (!strcmp(ri->request_method, "MKCOL")) {
|
|
|
|
- mkcol(conn, path);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- /* 11.4. PATCH method
|
|
|
|
- * This method is not supported for static resources,
|
|
|
|
- * only for scripts (Lua, CGI) and callbacks. */
|
|
|
|
- send_http_error(conn,
|
|
|
|
- 405,
|
|
|
|
- "%s method not allowed",
|
|
|
|
- conn->request_info.request_method);
|
|
|
|
|
|
+ /* 11. Handle put/delete/mkcol requests */
|
|
|
|
+ if (is_put_or_delete_request) {
|
|
|
|
+ /* 11.1. PUT method */
|
|
|
|
+ if (!strcmp(ri->request_method, "PUT")) {
|
|
|
|
+ put_file(conn, path);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
-
|
|
|
|
- /* 11. File does not exist, or it was configured that it should be
|
|
|
|
- * hidden */
|
|
|
|
- if (!is_found || (must_hide_file(conn, path))) {
|
|
|
|
- send_http_error(conn, 404, "%s", "Not found");
|
|
|
|
|
|
+ /* 11.2. DELETE method */
|
|
|
|
+ if (!strcmp(ri->request_method, "DELETE")) {
|
|
|
|
+ delete_file(conn, path);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
-
|
|
|
|
- /* 12. Directory uris should end with a slash */
|
|
|
|
- if (file.stat.is_directory && (uri_len > 0)
|
|
|
|
- && (ri->local_uri[uri_len - 1] != '/')) {
|
|
|
|
- gmt_time_string(date, sizeof(date), &curtime);
|
|
|
|
- mg_printf(conn,
|
|
|
|
- "HTTP/1.1 301 Moved Permanently\r\n"
|
|
|
|
- "Location: %s/\r\n"
|
|
|
|
- "Date: %s\r\n"
|
|
|
|
- /* "Cache-Control: private\r\n" (= default) */
|
|
|
|
- "Content-Length: 0\r\n"
|
|
|
|
- "Connection: %s\r\n\r\n",
|
|
|
|
- ri->request_uri,
|
|
|
|
- date,
|
|
|
|
- suggest_connection_header(conn));
|
|
|
|
|
|
+ /* 11.3. MKCOL method */
|
|
|
|
+ if (!strcmp(ri->request_method, "MKCOL")) {
|
|
|
|
+ mkcol(conn, path);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+ /* 11.4. PATCH method
|
|
|
|
+ * This method is not supported for static resources,
|
|
|
|
+ * only for scripts (Lua, CGI) and callbacks. */
|
|
|
|
+ send_http_error(conn,
|
|
|
|
+ 405,
|
|
|
|
+ "%s method not allowed",
|
|
|
|
+ conn->request_info.request_method);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- /* 13. Handle other methods than GET/HEAD */
|
|
|
|
- /* 13.1. Handle PROPFIND */
|
|
|
|
- if (!strcmp(ri->request_method, "PROPFIND")) {
|
|
|
|
- handle_propfind(conn, path, &file.stat);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- /* 13.2. Handle OPTIONS for files */
|
|
|
|
- if (!strcmp(ri->request_method, "OPTIONS")) {
|
|
|
|
- /* This standard handler is only used for real files.
|
|
|
|
- * Scripts should support the OPTIONS method themselves, to allow a
|
|
|
|
- * maximum flexibility.
|
|
|
|
- * Lua and CGI scripts may fully support CORS this way (including
|
|
|
|
- * preflights). */
|
|
|
|
- send_options(conn);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- /* 13.3. everything but GET and HEAD (e.g. POST) */
|
|
|
|
- if (0 != strcmp(ri->request_method, "GET")
|
|
|
|
- && 0 != strcmp(ri->request_method, "HEAD")) {
|
|
|
|
- send_http_error(conn,
|
|
|
|
- 405,
|
|
|
|
- "%s method not allowed",
|
|
|
|
- conn->request_info.request_method);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ /* 11. File does not exist, or it was configured that it should be
|
|
|
|
+ * hidden */
|
|
|
|
+ if (!is_found || (must_hide_file(conn, path))) {
|
|
|
|
+ send_http_error(conn, 404, "%s", "Not found");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- /* 14. directories */
|
|
|
|
- if (file.stat.is_directory) {
|
|
|
|
- if (substitute_index_file(conn, path, sizeof(path), &file)) {
|
|
|
|
- /* 14.1. use a substitute file */
|
|
|
|
- /* TODO (high): substitute index may be a script resource.
|
|
|
|
- * define what should be possible in this case. */
|
|
|
|
|
|
+ /* 12. Directory uris should end with a slash */
|
|
|
|
+ if (file.stat.is_directory && (uri_len > 0)
|
|
|
|
+ && (ri->local_uri[uri_len - 1] != '/')) {
|
|
|
|
+ gmt_time_string(date, sizeof(date), &curtime);
|
|
|
|
+ mg_printf(conn,
|
|
|
|
+ "HTTP/1.1 301 Moved Permanently\r\n"
|
|
|
|
+ "Location: %s/\r\n"
|
|
|
|
+ "Date: %s\r\n"
|
|
|
|
+ /* "Cache-Control: private\r\n" (= default) */
|
|
|
|
+ "Content-Length: 0\r\n"
|
|
|
|
+ "Connection: %s\r\n\r\n",
|
|
|
|
+ ri->request_uri,
|
|
|
|
+ date,
|
|
|
|
+ suggest_connection_header(conn));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* 13. Handle other methods than GET/HEAD */
|
|
|
|
+ /* 13.1. Handle PROPFIND */
|
|
|
|
+ if (!strcmp(ri->request_method, "PROPFIND")) {
|
|
|
|
+ handle_propfind(conn, path, &file.stat);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ /* 13.2. Handle OPTIONS for files */
|
|
|
|
+ if (!strcmp(ri->request_method, "OPTIONS")) {
|
|
|
|
+ /* This standard handler is only used for real files.
|
|
|
|
+ * Scripts should support the OPTIONS method themselves, to allow a
|
|
|
|
+ * maximum flexibility.
|
|
|
|
+ * Lua and CGI scripts may fully support CORS this way (including
|
|
|
|
+ * preflights). */
|
|
|
|
+ send_options(conn);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ /* 13.3. everything but GET and HEAD (e.g. POST) */
|
|
|
|
+ if (0 != strcmp(ri->request_method, "GET")
|
|
|
|
+ && 0 != strcmp(ri->request_method, "HEAD")) {
|
|
|
|
+ send_http_error(conn,
|
|
|
|
+ 405,
|
|
|
|
+ "%s method not allowed",
|
|
|
|
+ conn->request_info.request_method);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* 14. directories */
|
|
|
|
+ if (file.stat.is_directory) {
|
|
|
|
+ if (substitute_index_file(conn, path, sizeof(path), &file)) {
|
|
|
|
+ /* 14.1. use a substitute file */
|
|
|
|
+ /* TODO (high): substitute index may be a script resource.
|
|
|
|
+ * define what should be possible in this case. */
|
|
|
|
+ } else {
|
|
|
|
+ /* 14.2. no substitute file */
|
|
|
|
+ if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING],
|
|
|
|
+ "yes")) {
|
|
|
|
+ handle_directory_request(conn, path);
|
|
} else {
|
|
} else {
|
|
- /* 14.2. no substitute file */
|
|
|
|
- if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING],
|
|
|
|
- "yes")) {
|
|
|
|
- handle_directory_request(conn, path);
|
|
|
|
- } else {
|
|
|
|
- send_http_error(conn,
|
|
|
|
- 403,
|
|
|
|
- "%s",
|
|
|
|
- "Error: Directory listing denied");
|
|
|
|
- }
|
|
|
|
- return;
|
|
|
|
|
|
+ send_http_error(conn,
|
|
|
|
+ 403,
|
|
|
|
+ "%s",
|
|
|
|
+ "Error: Directory listing denied");
|
|
}
|
|
}
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- handle_file_based_request(conn, path, &file);
|
|
|
|
|
|
+ handle_file_based_request(conn, path, &file);
|
|
#endif /* !defined(NO_FILES) */
|
|
#endif /* !defined(NO_FILES) */
|
|
|
|
|
|
#if 0
|
|
#if 0
|
|
@@ -10994,8 +10993,6 @@ handle_request(struct mg_connection *conn)
|
|
* Otherwise, begin_request() would need to perform auth checks and
|
|
* Otherwise, begin_request() would need to perform auth checks and
|
|
* redirects. */
|
|
* redirects. */
|
|
#endif
|
|
#endif
|
|
- }
|
|
|
|
- return;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|