1
0
mirror of https://github.com/lammertb/libhttp.git synced 2026-01-27 08:02:47 +03:00

Moved interpret_uri to own file

This commit is contained in:
Lammert Bies
2016-12-11 12:18:25 +01:00
parent 5788d36fc2
commit 38becc0b4b
3 changed files with 208 additions and 180 deletions

View File

@@ -88,6 +88,7 @@ LIB_SOURCES = src/libhttp.c \
src/httplib_handle_websocket_request.c \
src/httplib_inet_pton.c \
src/httplib_initialize_ssl.c \
src/httplib_interpret_uri.c \
src/httplib_is_authorized_for_put.c \
src/httplib_is_not_modified.c \
src/httplib_is_valid_http_method.c \

207
src/httplib_interpret_uri.c Normal file
View File

@@ -0,0 +1,207 @@
/*
* Copyright (c) 2016 Lammert Bies
* Copyright (c) 2013-2016 the Civetweb developers
* Copyright (c) 2004-2013 Sergey Lyubka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libhttp-private.h"
/*
* void XX_httplib_interpret_uri();
*
* The function XX_httplib_interpret_uri() interprets an URI and decides what
* type of request is involved. The function takes the following parameters:
*
* conn: in: The request (must be valid)
* filename: out: Filename
* filename_buf_len: in: Size of the filename buffer
* filep: out: file structure
* is_found: out: file is found (directly)
* is_script_resource: out: handled by a script?
* is_websocket_request: out: websocket connection?
* is_put_or_delete_request: out: put/delete file?
*/
void XX_httplib_interpret_uri( struct mg_connection *conn, char *filename, size_t filename_buf_len, struct file *filep, int *is_found, int *is_script_resource, int *is_websocket_request, int *is_put_or_delete_request ) {
/* TODO (high): Restructure this function */
#if !defined(NO_FILES)
const char *uri = conn->request_info.local_uri;
const char *root = conn->ctx->config[DOCUMENT_ROOT];
const char *rewrite;
struct vec a;
struct vec b;
int match_len;
char gz_path[PATH_MAX];
char const *accept_encoding;
int truncated;
#if !defined(NO_CGI)
char *p;
#endif
#else
(void)filename_buf_len; /* unused if NO_FILES is defined */
#endif
memset(filep, 0, sizeof(*filep));
*filename = 0;
*is_found = 0;
*is_script_resource = 0;
*is_put_or_delete_request = XX_httplib_is_put_or_delete_method(conn);
#if defined(USE_WEBSOCKET)
*is_websocket_request = XX_httplib_is_websocket_protocol(conn);
#if !defined(NO_FILES)
if (*is_websocket_request && conn->ctx->config[WEBSOCKET_ROOT]) {
root = conn->ctx->config[WEBSOCKET_ROOT];
}
#endif /* !NO_FILES */
#else /* USE_WEBSOCKET */
*is_websocket_request = 0;
#endif /* USE_WEBSOCKET */
#if !defined(NO_FILES)
/* Note that root == NULL is a regular use case here. This occurs,
* if all requests are handled by callbacks, so the WEBSOCKET_ROOT
* config is not required. */
if (root == NULL) {
/* all file related outputs have already been set to 0, just return
*/
return;
}
/* Using buf_len - 1 because memmove() for PATH_INFO may shift part
* of the path one byte on the right.
* If document_root is NULL, leave the file empty. */
XX_httplib_snprintf( conn, &truncated, filename, filename_buf_len - 1, "%s%s", root, uri);
if (truncated) goto interpret_cleanup;
rewrite = conn->ctx->config[REWRITE];
while ((rewrite = XX_httplib_next_option(rewrite, &a, &b)) != NULL) {
if ((match_len = XX_httplib_match_prefix(a.ptr, a.len, uri)) > 0) {
XX_httplib_snprintf(conn, &truncated, filename, filename_buf_len - 1, "%.*s%s", (int)b.len, b.ptr, uri + match_len);
break;
}
}
if (truncated) goto interpret_cleanup;
/* Local file path and name, corresponding to requested URI
* is now stored in "filename" variable. */
if (XX_httplib_stat(conn, filename, filep)) {
#if !defined(NO_CGI)
/* File exists. Check if it is a script type. */
if (0
#if !defined(NO_CGI)
|| XX_httplib_match_prefix(conn->ctx->config[CGI_EXTENSIONS],
strlen(conn->ctx->config[CGI_EXTENSIONS]),
filename) > 0
#endif
) {
/* The request addresses a CGI script or a Lua script. The URI
* corresponds to the script itself (like /path/script.cgi),
* and there is no additional resource path
* (like /path/script.cgi/something).
* Requests that modify (replace or delete) a resource, like
* PUT and DELETE requests, should replace/delete the script
* file.
* Requests that read or write from/to a resource, like GET and
* POST requests, should call the script and return the
* generated response. */
*is_script_resource = !*is_put_or_delete_request;
}
#endif /* !defined(NO_CGI) */
*is_found = 1;
return;
}
/* If we can't find the actual file, look for the file
* with the same name but a .gz extension. If we find it,
* use that and set the gzipped flag in the file struct
* to indicate that the response need to have the content-
* encoding: gzip header.
* We can only do this if the browser declares support. */
if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
if (strstr(accept_encoding, "gzip") != NULL) {
XX_httplib_snprintf( conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", filename);
if (truncated) {
goto interpret_cleanup;
}
if (XX_httplib_stat(conn, gz_path, filep)) {
if (filep) {
filep->gzipped = 1;
*is_found = 1;
}
/* Currently gz files can not be scripts. */
return;
}
}
}
#if !defined(NO_CGI)
/* Support PATH_INFO for CGI scripts. */
for (p = filename + strlen(filename); p > filename + 1; p--) {
if (*p == '/') {
*p = '\0';
if ((0
#if !defined(NO_CGI)
|| XX_httplib_match_prefix(conn->ctx->config[CGI_EXTENSIONS],
strlen(conn->ctx->config[CGI_EXTENSIONS]),
filename) > 0
#endif
) && XX_httplib_stat(conn, filename, filep)) {
/* Shift PATH_INFO block one character right, e.g.
* "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
* conn->path_info is pointing to the local variable "path"
* declared in XX_httplib_handle_request(), so PATH_INFO is not valid
* after XX_httplib_handle_request returns. */
conn->path_info = p + 1;
memmove(p + 2, p + 1, strlen(p + 1) + 1); /* +1 is for
* trailing \0 */
p[1] = '/';
*is_script_resource = 1;
break;
} else *p = '/';
}
}
#endif /* !defined(NO_CGI) */
#endif /* !defined(NO_FILES) */
return;
#if !defined(NO_FILES)
/* Reset all outputs */
interpret_cleanup:
memset(filep, 0, sizeof(*filep));
*filename = 0;
*is_found = 0;
*is_script_resource = 0;
*is_websocket_request = 0;
*is_put_or_delete_request = 0;
#endif /* !defined(NO_FILES) */
} /* XX_httplib_interpret_uri */

View File

@@ -3340,183 +3340,3 @@ int XX_httplib_is_put_or_delete_method( const struct mg_connection *conn ) {
return s != NULL && (!strcmp(s, "PUT") || !strcmp(s, "DELETE") || !strcmp(s, "MKCOL") || !strcmp(s, "PATCH"));
} /* X_httplib_is_put_or_delete_method */
/*
* void XX_httplib_interpret_uri();
*
* The function XX_httplib_interpret_uri() interprets an URI and decides what
* type of request is involved. The function takes the following parameters:
*
* conn: in: The request (must be valid)
* filename: out: Filename
* filename_buf_len: in: Size of the filename buffer
* filep: out: file structure
* is_found: out: file is found (directly)
* is_script_resource: out: handled by a script?
* is_websocket_request: out: websocket connection?
* is_put_or_delete_request: out: put/delete file?
*/
void XX_httplib_interpret_uri( struct mg_connection *conn, char *filename, size_t filename_buf_len, struct file *filep, int *is_found, int *is_script_resource, int *is_websocket_request, int *is_put_or_delete_request ) {
/* TODO (high): Restructure this function */
#if !defined(NO_FILES)
const char *uri = conn->request_info.local_uri;
const char *root = conn->ctx->config[DOCUMENT_ROOT];
const char *rewrite;
struct vec a;
struct vec b;
int match_len;
char gz_path[PATH_MAX];
char const *accept_encoding;
int truncated;
#if !defined(NO_CGI)
char *p;
#endif
#else
(void)filename_buf_len; /* unused if NO_FILES is defined */
#endif
memset(filep, 0, sizeof(*filep));
*filename = 0;
*is_found = 0;
*is_script_resource = 0;
*is_put_or_delete_request = XX_httplib_is_put_or_delete_method(conn);
#if defined(USE_WEBSOCKET)
*is_websocket_request = XX_httplib_is_websocket_protocol(conn);
#if !defined(NO_FILES)
if (*is_websocket_request && conn->ctx->config[WEBSOCKET_ROOT]) {
root = conn->ctx->config[WEBSOCKET_ROOT];
}
#endif /* !NO_FILES */
#else /* USE_WEBSOCKET */
*is_websocket_request = 0;
#endif /* USE_WEBSOCKET */
#if !defined(NO_FILES)
/* Note that root == NULL is a regular use case here. This occurs,
* if all requests are handled by callbacks, so the WEBSOCKET_ROOT
* config is not required. */
if (root == NULL) {
/* all file related outputs have already been set to 0, just return
*/
return;
}
/* Using buf_len - 1 because memmove() for PATH_INFO may shift part
* of the path one byte on the right.
* If document_root is NULL, leave the file empty. */
XX_httplib_snprintf( conn, &truncated, filename, filename_buf_len - 1, "%s%s", root, uri);
if (truncated) goto interpret_cleanup;
rewrite = conn->ctx->config[REWRITE];
while ((rewrite = XX_httplib_next_option(rewrite, &a, &b)) != NULL) {
if ((match_len = XX_httplib_match_prefix(a.ptr, a.len, uri)) > 0) {
XX_httplib_snprintf(conn, &truncated, filename, filename_buf_len - 1, "%.*s%s", (int)b.len, b.ptr, uri + match_len);
break;
}
}
if (truncated) goto interpret_cleanup;
/* Local file path and name, corresponding to requested URI
* is now stored in "filename" variable. */
if (XX_httplib_stat(conn, filename, filep)) {
#if !defined(NO_CGI)
/* File exists. Check if it is a script type. */
if (0
#if !defined(NO_CGI)
|| XX_httplib_match_prefix(conn->ctx->config[CGI_EXTENSIONS],
strlen(conn->ctx->config[CGI_EXTENSIONS]),
filename) > 0
#endif
) {
/* The request addresses a CGI script or a Lua script. The URI
* corresponds to the script itself (like /path/script.cgi),
* and there is no additional resource path
* (like /path/script.cgi/something).
* Requests that modify (replace or delete) a resource, like
* PUT and DELETE requests, should replace/delete the script
* file.
* Requests that read or write from/to a resource, like GET and
* POST requests, should call the script and return the
* generated response. */
*is_script_resource = !*is_put_or_delete_request;
}
#endif /* !defined(NO_CGI) */
*is_found = 1;
return;
}
/* If we can't find the actual file, look for the file
* with the same name but a .gz extension. If we find it,
* use that and set the gzipped flag in the file struct
* to indicate that the response need to have the content-
* encoding: gzip header.
* We can only do this if the browser declares support. */
if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
if (strstr(accept_encoding, "gzip") != NULL) {
XX_httplib_snprintf( conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", filename);
if (truncated) {
goto interpret_cleanup;
}
if (XX_httplib_stat(conn, gz_path, filep)) {
if (filep) {
filep->gzipped = 1;
*is_found = 1;
}
/* Currently gz files can not be scripts. */
return;
}
}
}
#if !defined(NO_CGI)
/* Support PATH_INFO for CGI scripts. */
for (p = filename + strlen(filename); p > filename + 1; p--) {
if (*p == '/') {
*p = '\0';
if ((0
#if !defined(NO_CGI)
|| XX_httplib_match_prefix(conn->ctx->config[CGI_EXTENSIONS],
strlen(conn->ctx->config[CGI_EXTENSIONS]),
filename) > 0
#endif
) && XX_httplib_stat(conn, filename, filep)) {
/* Shift PATH_INFO block one character right, e.g.
* "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
* conn->path_info is pointing to the local variable "path"
* declared in XX_httplib_handle_request(), so PATH_INFO is not valid
* after XX_httplib_handle_request returns. */
conn->path_info = p + 1;
memmove(p + 2, p + 1, strlen(p + 1) + 1); /* +1 is for
* trailing \0 */
p[1] = '/';
*is_script_resource = 1;
break;
} else *p = '/';
}
}
#endif /* !defined(NO_CGI) */
#endif /* !defined(NO_FILES) */
return;
#if !defined(NO_FILES)
/* Reset all outputs */
interpret_cleanup:
memset(filep, 0, sizeof(*filep));
*filename = 0;
*is_found = 0;
*is_script_resource = 0;
*is_websocket_request = 0;
*is_put_or_delete_request = 0;
#endif /* !defined(NO_FILES) */
} /* XX_httplib_interpret_uri */