From 089431e9023709e1868bdd959512a321363e9c0d Mon Sep 17 00:00:00 2001 From: Relintai Date: Thu, 30 Jun 2022 21:09:54 +0200 Subject: [PATCH] Remvoed httpio, as it apparently works differently that how I originally thought. --- modules/web/SCsub | 3 - modules/web/http_server_simple/httpio.md | 3 - .../web/http_server_simple/httpio/.gitignore | 1 - modules/web/http_server_simple/httpio/LICENSE | 21 - .../web/http_server_simple/httpio/README.md | 120 -- modules/web/http_server_simple/httpio/http.c | 298 ---- modules/web/http_server_simple/httpio/http.h | 237 --- .../web/http_server_simple/httpio/httpio.c | 1330 ----------------- .../web/http_server_simple/httpio/httpio.h | 185 --- 9 files changed, 2198 deletions(-) delete mode 100644 modules/web/http_server_simple/httpio.md delete mode 100644 modules/web/http_server_simple/httpio/.gitignore delete mode 100644 modules/web/http_server_simple/httpio/LICENSE delete mode 100644 modules/web/http_server_simple/httpio/README.md delete mode 100644 modules/web/http_server_simple/httpio/http.c delete mode 100644 modules/web/http_server_simple/httpio/http.h delete mode 100644 modules/web/http_server_simple/httpio/httpio.c delete mode 100644 modules/web/http_server_simple/httpio/httpio.h diff --git a/modules/web/SCsub b/modules/web/SCsub index 4eabebc9b..d32ed5761 100644 --- a/modules/web/SCsub +++ b/modules/web/SCsub @@ -27,9 +27,6 @@ sources = [ "http_server_simple/http_server_simple.cpp", "http_server_simple/web_server_simple.cpp", "http_server_simple/simple_web_server_request.cpp", - - "http_server_simple/httpio/http.c", - "http_server_simple/httpio/httpio.c", ] if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes': diff --git a/modules/web/http_server_simple/httpio.md b/modules/web/http_server_simple/httpio.md deleted file mode 100644 index 33ef95935..000000000 --- a/modules/web/http_server_simple/httpio.md +++ /dev/null @@ -1,3 +0,0 @@ -https://github.com/fetisov/httpio - -8c56b550316e064842360eeddf2abb626df9123f \ No newline at end of file diff --git a/modules/web/http_server_simple/httpio/.gitignore b/modules/web/http_server_simple/httpio/.gitignore deleted file mode 100644 index 612cb8c3a..000000000 --- a/modules/web/http_server_simple/httpio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/tests/* diff --git a/modules/web/http_server_simple/httpio/LICENSE b/modules/web/http_server_simple/httpio/LICENSE deleted file mode 100644 index 9857f7f93..000000000 --- a/modules/web/http_server_simple/httpio/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 Fetisov Sergey - -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. diff --git a/modules/web/http_server_simple/httpio/README.md b/modules/web/http_server_simple/httpio/README.md deleted file mode 100644 index 96b7fbee6..000000000 --- a/modules/web/http_server_simple/httpio/README.md +++ /dev/null @@ -1,120 +0,0 @@ -# httpio -Cross Platform parser and response generator for the HTTP protocol. - -Library has the simple API to embed to the custom systems. - -Parser functions: -- Parses the HTTP stream on the fly -- Does not use the dynamic allocation (uses predefined connection buffer as the simple pool) -- Not used space of the connection buffer can be used as the network receiving buffer -- Supports the keep-alive multiple requests and various types of POST request - -Generator functions: -- As well as the parser it does not use the dynamic allocation -- Organized by a ring buffer -- Supports the chunked transfer encoding - -# Parser example (stdin instead the socket) -```c -#include -#include "httpio.h" - -static char in_pool[1024]; - -int main(int argc, const char **argv) -{ - FILE *f; - httpi_t *in; - f = argc == 2 ? fopen(argv[1], "rb") : stdin; - in = httpi_init(in_pool, 1024); - while (1) - { - int size; - char *data; - int status = httpi_pull(in); - switch (status) - { - case HTTP_IN_NODATA: - /* data input */ - httpi_get_state(in, &data, &size); - size = fread(data, 1, size, f); - httpi_push(in, data, size); - if (size == 0) return 0; - continue; - case HTTP_IN_REQUEST: - printf("page %s requested\n", httpi_request(in)->uri); - continue; - case HTTP_IN_POSTDATA: - printf("new chunk of POST data \"%s\"\n", httpi_posted(in)->name); - continue; - case HTTP_IN_FINISHED: - printf("request finished\n"); - continue; - default: - printf("invalid request!\n"); - return 0; - } - } -} -``` -Example input: -```http -POST /cgi-bin/login.cgi HTTP/1.1 -Host: www.tutorialspoint.com -Content-Type: application/x-www-form-urlencoded -Content-Length: 35 -Accept-Language: en-us -Accept-Encoding: gzip, deflate -Connection: Keep-Alive - -login=Petya%20Vasechkin&password=qq -``` -Example output: -``` -page /cgi-bin/login.cgi requested -new chunk of POST data "login" -new chunk of POST data "password" -request finished -``` - -# Response generator example (stdout instead the socket) -```c -#include -#include "httpio.h" - -static char out_pool[1024]; - -int main(int argc, const char **argv) -{ - FILE *f; - httpo_t *out; - http_resp_t resp; - char *data; - int size; - out = httpo_init(out_pool, 1024); - http_resp_init(&resp, 200, MIME_TEXT_HTML, RESPF_KEEPALIVE | RESPF_CHUNKED | RESPF_NOCACH); - httpo_write_resp(out, &resp); - httpo_write_data(out, "first data chunk", 16); - httpo_write_data(out, "the second data chunk", 21); - httpo_finished(out); - httpo_state(out, &data, &size); - fwrite(data, 1, size, stdout); - return 0; -} -``` - -Example output: -```http -HTTP/1.1 200 OK -Content-Language: en -Content-Type: text/html -Connection: keep-alive -Cache-Control: no-store, no-cache -Transfer-Encoding: chunked - -10 -first data chunk -15 -the second data chunk -0 -``` diff --git a/modules/web/http_server_simple/httpio/http.c b/modules/web/http_server_simple/httpio/http.c deleted file mode 100644 index 1e47860e8..000000000 --- a/modules/web/http_server_simple/httpio/http.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 by Sergey Fetisov - * - * 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 "http.h" - -#ifdef __cplusplus -extern "C" { -#endif - -const char MIME_APP_ATOM[] = "application/atom+xml"; -const char MIME_APP_JSON[] = "application/json"; -const char MIME_APP_JS[] = "application/javascript"; -const char MIME_APP_OCTSTR[] = "application/octet-stream"; -const char MIME_APP_PDF[] = "application/pdf"; -const char MIME_APP_PS[] = "application/postscript"; -const char MIME_APP_XHTML[] = "application/xhtml+xml"; -const char MIME_APP_XML[] = "application/xml-dtd"; -const char MIME_APP_ZIP[] = "application/zip"; -const char MIME_APP_GZIP[] = "application/x-gzip"; -const char MIME_APP_BTOR[] = "application/x-bittorrent"; -const char MIME_APP_TEX[] = "application/x-tex"; -const char MIME_URLENCODED[] = "application/x-www-form-urlencoded"; -const char MIME_TEXT_HTML[] = "text/html"; -const char MIME_TEXT_JS[] = "text/javascript"; -const char MIME_TEXT_PLAIN[] = "text/plain"; -const char MIME_TEXT_XML[] = "text/xml"; -const char MIME_TEXT_CSS[] = "text/css"; -const char MIME_IMAGE_GIF[] = "image/gif"; -const char MIME_IMAGE_JPEG[] = "image/jpeg"; -const char MIME_IMAGE_PJPEG[] = "image/pjpeg"; -const char MIME_IMAGE_PNG[] = "image/png"; -const char MIME_IMAGE_SVG[] = "image/svg+xml"; -const char MIME_IMAGE_TIFF[] = "image/tiff"; -const char MIME_IMAGE_ICON[] = "image/vnd.microsoft.icon"; -const char MIME_IMAGE_WBMP[] = "image/vnd.wap.wbmp"; -const char MIME_MPART_MIXED[] = "multipart/mixed"; -const char MIME_MPART_ALT[] = "multipart/alternative"; -const char MIME_MPART_REL[] = "multipart/related"; -const char MIME_MPART_FORM[] = "multipart/form-data"; -const char MIME_MPART_SIGN[] = "multipart/signed"; -const char MIME_MPART_ENCR[] = "multipart/encrypted"; - -const char *mime_list[] = -{ - MIME_TEXT_HTML, - MIME_TEXT_PLAIN, - MIME_URLENCODED, - MIME_APP_XHTML, - MIME_APP_XML, - MIME_TEXT_CSS, - MIME_TEXT_JS, - MIME_TEXT_XML, - MIME_IMAGE_JPEG, - MIME_IMAGE_PNG, - MIME_IMAGE_GIF, - MIME_IMAGE_SVG, - MIME_MPART_FORM, - MIME_MPART_MIXED, - MIME_APP_JS, - MIME_APP_JSON, - MIME_APP_ATOM, - MIME_APP_OCTSTR, - MIME_APP_PDF, - MIME_APP_PS, - MIME_APP_ZIP, - MIME_APP_GZIP, - MIME_APP_BTOR, - MIME_APP_TEX, - MIME_IMAGE_PJPEG, - MIME_IMAGE_TIFF, - MIME_IMAGE_ICON, - MIME_IMAGE_WBMP, - MIME_MPART_ALT, - MIME_MPART_REL, - MIME_MPART_SIGN, - MIME_MPART_ENCR, - NULL -}; - -struct http_code -{ - int code; - const char *str; -}; - -static struct http_code http_code_list[] = -{ - { 100, "Continue" }, - { 101, "Switching Protocols" }, - { 102, "Processing" }, - { 200, "OK" }, - { 201, "Created" }, - { 202, "Accepted" }, - { 203, "Non-Authoritative Information" }, - { 204, "No Content" }, - { 205, "Reset Content" }, - { 206, "Partial Content" }, - { 207, "Multi Status" }, - { 300, "Multiple Choices" }, - { 301, "Moved Permanently" }, - { 302, "Moved Temporarily" }, - { 303, "See Other" }, - { 304, "Not Modified" }, - { 305, "Use Proxy" }, - { 306, "Switch Proxy" }, - { 307, "Temporary Redirect" }, - { 400, "Bad Request" }, - { 401, "Unauthorized" }, - { 402, "Payment Required" }, - { 403, "Forbidden" }, - { 404, "Not Found" }, - { 405, "Method Not Allowed" }, - { 406, "Not Acceptable" }, - { 407, "Proxy Authentication Required" }, - { 408, "Request Time-out" }, - { 409, "Conflict" }, - { 410, "Gone" }, - { 411, "Length Required" }, - { 412, "Precondition Failed" }, - { 413, "Request Entity Too Large" }, - { 414, "Request-URI Too Large" }, - { 415, "Unsupported Media Type" }, - { 416, "Requested Range Not Satisfiable" }, - { 417, "Expectation Failed" }, - { 422, "Unprocessable Entity" }, - { 423, "Locked" }, - { 424, "Failed Dependency" }, - { 425, "Unordered Collection" }, - { 426, "Upgrade Required" }, - { 444, "No Response" }, - { 449, "Retry With" }, - { 450, "Blocked by Windows Parental Controls" }, - { 451, "Unavailable For Legal Reasons" }, - { 500, "Internal Server Error" }, - { 501, "Not Implemented" }, - { 502, "Bad Gateway" }, - { 503, "Service Unavailable" }, - { 504, "Gateway Time-out" }, - { 505, "HTTP Version not supported" }, - { 506, "Variant Also Negotiates" }, - { 507, "Insufficient Storage" }, - { 508, "Unknown" }, - { 509, "Bandwidth Limit Exceeded" }, - { 510, "Not Extended" } -}; - -static const char *CONN_TYPE_STR[] = -{ - "", "close", "keep-alive" -}; - -const char *http_req_val(const http_req_t *req, const char *param, const char *def) -{ - int i; - for (i = 0; i < req->nparams; i++) - if (strcmp(req->params[i], param) == 0) - return req->values[i]; - return def; -} - -void http_resp_init(http_resp_t *resp, int code, const char *mime, int flags) -{ - memset(resp, 0, sizeof(http_resp_t)); - resp->code = code; - resp->connection = flags & RESPF_KEEPALIVE ? CT_KEEP_ALIVE : CT_CLOSE; - resp->content.type = mime; - resp->content.length = -1; - resp->content.language = "en"; - resp->cache_control = flags & RESPF_NOCACH ? "no-store, no-cache" : NULL; - if (flags & RESPF_DEFLATE) resp->content.encoding = "deflate"; else - if (flags & RESPF_GZIP) resp->content.encoding = "gzip"; - resp->transfer_encoding = flags & RESPF_CHUNKED ? TENC_CHUNKED : TENC_NONE; -} - -const char *http_dict_mime(const char *mime) -{ - int i; - if (mime == NULL) return NULL; - for (i = 0; mime_list[i] != NULL; i++) - if (strcmp(mime_list[i], mime) == 0) - return mime_list[i]; - return NULL; -} - -int http_resp_len(const http_resp_t *resp) -{ - int tmp; - return http_resp_str(resp, (char *)&tmp, sizeof(tmp)); -} - -#if defined(__WINNT__) || defined(_WIN32) || defined(_WIN64) -int correct_snprintf(char *buff, int buff_size, const char *fmt, ...) -{ - int res; - va_list args; - va_start(args, fmt); - res = vsnprintf(buff, buff_size, fmt, args); - if (res < 0) res = _vscprintf(fmt, args); - va_end(args); - return res; -} -#else -#define correct_snprintf snprintf -#endif - -int http_resp_str(const http_resp_t *resp, char *str, int size) -{ -#define PRN(fmt, arg) \ - { \ - n = correct_snprintf(str, size, fmt, arg); \ - str += n; \ - size -= n; \ - res += n; \ - if (size < 0) size = 0; \ - } - -#define PRNSTR(prop, field) if (field != NULL) PRN(prop ": %s\r\n", field) - - int res, n; - res = 0; - - PRN("HTTP/1.1 %d ", resp->code); - PRN("%s\r\n", http_code_str(resp->code)); - if (resp->content.disp.disp != NULL) - { - PRN("Content-Disposition %s", resp->content.disp.disp); - if (resp->content.disp.disp_name != NULL) - PRN(" name=\"%s\"", resp->content.disp.disp_name); - if (resp->content.disp.disp_file != NULL) - PRN(" filename=\"%s\"", resp->content.disp.disp_file); - PRN("%s", "\r\n"); - } - PRNSTR("Content-Encoding", resp->content.encoding); - PRNSTR("Content-Language", resp->content.language); - if (resp->content.length > 0) - PRN("Content-Length: %d\r\n", resp->content.length); - PRNSTR("Content-Location", resp->content.location); - PRNSTR("Content-MD5", resp->content.md5); - /* TODO: http_rng_t range; */ - PRNSTR("Content-Type", resp->content.type); - PRNSTR("Content-Version", resp->content.ver); - PRNSTR("Expires", resp->content.expires); - PRNSTR("Last-Modified", resp->content.modified); - PRNSTR("Link", resp->content.link); - PRNSTR("Title", resp->content.title); - PRN("Connection: %s\r\n", CONN_TYPE_STR[resp->connection]); - PRNSTR("Cache-Control", resp->cache_control); - PRNSTR("ETag", resp->etag); - PRNSTR("Location", resp->location); - PRNSTR("Proxy-Authenticate", resp->proxy_authenticate); - PRNSTR("Public", resp->Public); - if (resp->retry_after > 0) - PRN("Retry-After: %d\r\n", resp->retry_after); - PRNSTR("Server", resp->server); - if (resp->transfer_encoding == TENC_CHUNKED) - PRN("Transfer-Encoding: %s\r\n", "chunked"); - PRNSTR("Vary", resp->vary); - PRNSTR("WWW-Authenticate", resp->www_authenticate); - if (resp->exthdr != NULL) - PRN("%s", resp->exthdr); - PRN("%s", "\r\n"); - return res; -} - -const char *http_code_str(int code) -{ - int i, n; - n = sizeof(http_code_list) / sizeof(struct http_code); - for (i = 0; i < n; i++) - if (http_code_list[i].code == code) - return http_code_list[i].str; - return ""; -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/web/http_server_simple/httpio/http.h b/modules/web/http_server_simple/httpio/http.h deleted file mode 100644 index 706bb0bc4..000000000 --- a/modules/web/http_server_simple/httpio/http.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 by Sergey Fetisov - * - * 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. - */ - -#ifndef HTTP_H -#define HTTP_H - -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef HTTP_REQ_MAX_PARAMS -#define HTTP_REQ_MAX_PARAMS 16 -#endif - -#ifndef HTTP_REQ_MAX_ACCEPT -#define HTTP_REQ_MAX_ACCEPT 8 -#endif - -extern const char MIME_APP_ATOM[]; /* application/atom+xml */ -extern const char MIME_APP_JSON[]; /* application/json */ -extern const char MIME_APP_JS[]; /* application/javascript */ -extern const char MIME_APP_OCTSTR[]; /* application/octet-stream */ -extern const char MIME_APP_PDF[]; /* application/pdf */ -extern const char MIME_APP_PS[]; /* application/postscript */ -extern const char MIME_APP_XHTML[]; /* application/xhtml+xml */ -extern const char MIME_APP_XML[]; /* application/xml-dtd */ -extern const char MIME_APP_ZIP[]; /* application/zip */ -extern const char MIME_APP_GZIP[]; /* application/x-gzip */ -extern const char MIME_APP_BTOR[]; /* application/x-bittorrent */ -extern const char MIME_APP_TEX[]; /* application/x-tex */ -extern const char MIME_URLENCODED[]; /* application/x-www-form-urlencoded */ -extern const char MIME_TEXT_HTML[]; /* text/html */ -extern const char MIME_TEXT_JS[]; /* text/javascript */ -extern const char MIME_TEXT_PLAIN[]; /* text/plain */ -extern const char MIME_TEXT_XML[]; /* text/xml */ -extern const char MIME_TEXT_CSS[]; /* text/css */ -extern const char MIME_IMAGE_GIF[]; /* image/gif */ -extern const char MIME_IMAGE_JPEG[]; /* image/jpeg */ -extern const char MIME_IMAGE_PJPEG[]; /* image/pjpeg */ -extern const char MIME_IMAGE_PNG[]; /* image/png */ -extern const char MIME_IMAGE_SVG[]; /* image/svg+xml */ -extern const char MIME_IMAGE_TIFF[]; /* image/tiff */ -extern const char MIME_IMAGE_ICON[]; /* image/vnd.microsoft.icon */ -extern const char MIME_IMAGE_WBMP[]; /* image/vnd.wap.wbmp */ -extern const char MIME_MPART_MIXED[]; /* multipart/mixed */ -extern const char MIME_MPART_ALT[]; /* multipart/alternative */ -extern const char MIME_MPART_REL[]; /* multipart/related */ -extern const char MIME_MPART_FORM[]; /* multipart/form-data */ -extern const char MIME_MPART_SIGN[]; /* multipart/signed */ -extern const char MIME_MPART_ENCR[]; /* multipart/encrypted */ - -typedef enum http_method -{ - METHOD_NONE, - METHOD_GET, - METHOD_POST, - METHOD_HEAD, - METHOD_PUT, - METHOD_CONNECT, - METHOD_OPTIONS, - METHOD_DELETE, - METHOD_TRACE, - METHOD_PATCH -} http_mt_t; - -typedef enum http_conn_type -{ - CT_NONE, - CT_CLOSE, - CT_KEEP_ALIVE -} http_ct_t; - -/* http content disposition */ -typedef struct http_cdh -{ - const char *disp; /* Content-Disposition: [form-data]; name="File1"; filename="photo.jpg" */ - const char *disp_name; /* Content-Disposition: form-data; name="[File1]"; filename="photo.jpg" */ - const char *disp_file; /* Content-Disposition: form-data; name="File1"; filename="[photo.jpg]" */ -} http_cdh_t; - -typedef struct http_range -{ - uint32_t range_size; - uint32_t range_from; - uint32_t range_to; -} http_rng_t; - -/* http response/request entity */ - -typedef struct http_cont -{ - http_cdh_t disp; /* Content-Disposition: [form-data; name="File1"; filename="photo.jpg"] */ - const char *encoding; /* Content-Encoding: [...] */ - const char *language; /* Content-Language: [en, ase, ru] */ - int length; /* Content-Length: [123] */ - const char *location; /* Content-Location: [...] */ - const char *md5; /* Content-MD5: [Q2hlY2sgSW50ZWdyaXR5IQ==] */ - http_rng_t range; /* Content-Range: [64397516-80496894/160993792] */ - const char *type; /* Content-Type: [multipart/form-data] */ - const char *boundary; /* Content-Type: multipart/form-data; boundary="[Asrf456BGe4h]" */ - const char *charset; /* Content-Type: Content-Type: text/html; charset=[UTF-8] */ - const char *ver; /* Content-Version: [...] */ - const char *expires; /* Expires: [Tue, 31 Jan 2012 15:02:53 GMT] */ - const char *modified; /* Last-Modified: [...] */ - const char *link; /* link: [...] */ - const char *title; /* Title: [...] */ -} http_cont_t; - -/* http transfer encoding */ -typedef enum http_tenc -{ - TENC_NONE, /* - */ - TENC_CHUNKED /* Transfer-Encoding: chunked */ -} http_tenc_t; - -/* http transfer encoding */ -typedef struct httpaccept -{ - int count; - const char *type[HTTP_REQ_MAX_ACCEPT]; /* text/html */ - int level[HTTP_REQ_MAX_ACCEPT]; /* level=[1] */ - float q[HTTP_REQ_MAX_ACCEPT]; /* q=[0.8] */ -} httpaccept_t; - -typedef struct http_req -{ - /* request line */ - http_mt_t method; /* GET */ - const char *uri; /* /path */ - int nparams; /* */ - const char *params[HTTP_REQ_MAX_PARAMS]; /* param1, param2 */ - const char *values[HTTP_REQ_MAX_PARAMS]; /* value1, value2 */ - const char *ver; /* HTTP/1.1 */ - - /* general header */ - http_ct_t connection; /* Connection: [keep-alive] */ - char *via; /* Via: [1.0 fred, 1.1 example.com] */ - - /* request header */ - httpaccept_t accept; - const char *accept_charset; /* Accept-Charset: [utf-8] */ - const char *accept_encoding; /* Accept-Encoding: [gzip, deflate] */ - const char *accept_language; /* Accept-Language: [en-US;q=0.5,en;q=0.3] */ - const char *authorization; /* Authorization: [Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==] */ - const char *expect; /* Expect: [100-continue] */ - const char *from; /* From: [user@example.com] */ - const char *host; /* Host: [wikipedia.org] */ - const char *if_match; /* If-Match: "[737060cd8c284d8af7ad3082f209582d]" */ - const char *if_modified_since; /* If-Modified-Since: [Sat, 29 Oct 1994 19:43:31 GMT] */ - const char *if_none_match; /* If-None-Match: "[737060cd8c284d8af7ad3082f209582d]" */ - const char *if_range; /* If-Range: "[737060cd8c284d8af7ad3082f209582d]" */ - const char *if_unmodified_since; /* If-Unmodified-Since: [Sat, 29 Oct 1994 19:43:31 GMT] */ - int keep_alive; /* Keep-Alive: [300] */ - int max_forwards; /* Max-Forwards: [10] */ - const char *proxy_authorization; /* Proxy-Authorization: [Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==] */ - http_rng_t range; /* Range: bytes=[50000-99999],250000-399999,500000- */ - const char *referer; /* Referer: [http://en.wikipedia.org/wiki/Main_Page] */ - const char *te; /* TE: [trailers, deflate] */ - const char *user_agent; /* User-Agent: [Mozilla/5.0] */ - - /* content and cookies */ - http_cont_t content; /**/ - const char *cookie; /* Cookie: [Cookie data] */ -} http_req_t; - -typedef enum http_resp_flag -{ - RESPF_NONE = 0, - RESPF_KEEPALIVE = 1, - RESPF_CHUNKED = 2, - RESPF_NOCACH = 4, - RESPF_DEFLATE = 8, - RESPF_GZIP = 16 -} http_respf_t; - -typedef struct http_resp -{ - - char *mime_ver; /* MIME-Version: 1.0 */ - char *pragma; /* Pragma: [no-cache] */ - int code; /* HTTP/1.1 [200] OK */ - http_cont_t content; /**/ - http_ct_t connection; /* Connection: [keep-alive] */ - const char *cache_control; /* Cache-Control: [no-cache] */ - const char *etag; /* ETag: "[56d-9989200-1132c580]" */ - const char *location; /* Location: [http://example.com/about.html#contacts] */ - const char *proxy_authenticate; /* Proxy-Authenticate: [...] */ - const char *Public; /* Public: [...] */ - int retry_after; /* Retry-After: [123] */ - const char *server; /* Server: [Name] */ - http_tenc_t transfer_encoding; /* Transfer-Encoding: [chunked] */ - const char *vary; /* Vary: [...] */ - const char *www_authenticate; /* WWW-Authenticate: [...] */ - char *upgrade; /* Upgrade: [HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11] */ - const char *exthdr; /* extended header options */ -} http_resp_t; - -const char *http_req_val(const http_req_t *req, const char *param, const char *def); -void http_resp_init(http_resp_t *resp, int code, const char *mime, int flags); -const char *http_dict_mime(const char *mime); -const char *http_code_str(int code); -int http_resp_len(const http_resp_t *resp); -int http_resp_str(const http_resp_t *resp, char *str, int size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/modules/web/http_server_simple/httpio/httpio.c b/modules/web/http_server_simple/httpio/httpio.c deleted file mode 100644 index 039346b4d..000000000 --- a/modules/web/http_server_simple/httpio/httpio.c +++ /dev/null @@ -1,1330 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 by Sergey Fetisov - * - * 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 "httpio.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef MEM_ALIGNMENT -#define MEM_ALIGNMENT 4 -#endif - -#define CODE_DONE 0 -#define CODE_IN_EOF 1 -#define CODE_OUT_EOF 2 -#define CODE_CNT_LIM 3 -#define CODE_ERROR 4 -#define CODE_MEM_ERROR 5 - -#define STATE0_ERROR -1 -#define STATE0_RQLINE 0 -#define STATE0_RQHDR 1 -#define STATE0_URLENC 2 -#define STATE0_MPART_DATA 3 -#define STATE0_MPART_INIT 4 -#define STATE0_MPART_HDR 5 -#define STATE0_DONE 6 -#define STATE0_RESET 7 - -#define STATE_RQLINE_METHOD 0 -#define STATE_RQLINE_URI 1 -#define STATE_RQLINE_KEY 2 -#define STATE_RQLINE_VAL 3 -#define STATE_RQLINE_VER 4 -#define STATE_RQLINE_SKIPN 5 - -#define STATE_HDRRD_INIT 0 -#define STATE_HDRRD_KEYRD 1 -#define STATE_HDRRD_KEY 2 -#define STATE_HDRRD_SKIPWS 3 -#define STATE_HDRRD_VALRD 4 -#define STATE_HDRRD_VAL 5 -#define STATE_HDRRD_CSKIPWS 6 -#define STATE_HDRRD_CVALRD 7 -#define STATE_HDRRD_CVAL 8 -#define STATE_HDRRD_SKIPN 9 -#define STATE_HDRRD_LASTN 10 -#define STATE_HDRRD_FINISHED 11 - -#define STATE_MPART_DATARD 0 -#define STATE_MPART_NOTBNDRY 1 -#define STATE_MPART_ENDCHECK 2 -#define STATE_MPART_SKIPN 3 -#define STATE_MPART_SKIPMINUS 4 -#define STATE_MPART_SKIPR 5 -#define STATE_MPART_LASTN 6 -#define STATE_MPART_BNDRY 7 -#define STATE_MPART_FINISHED 8 - -#define STATE_URLENC_INIT 0 -#define STATE_URLENC_KEY 1 -#define STATE_URLENC_CHUNK 2 -#define STATE_URLENC_END 3 -#define STATE_URLENC_FINISHED 4 -#define STATE_URLENC_KEYRD 5 -#define STATE_URLENC_VALRD 6 - -typedef struct field_info fld_t; - -struct http_input -{ - struct - { - char *data; - int pos; - int size; - int tot; - } in; - struct - { - char *data; - int pos; - int size; - } out; - struct - { - char *data; - int size; - int used; - } pool; - struct - { - char stop; - } lexrd; - struct - { - char state; - } rqline; - struct - { - int state; - } hdrrd; - struct - { - int state; - const fld_t *field; - } rqhdr; - struct - { - int state; - } setter; - struct - { - int state; - int bndry_cntr; - int bndry_pos; - const char *bndry; - int bndry_size; - } mpart; - struct - { - int state; - char extra[4]; - } urlenc; - http_req_t req; - http_post_t post; - int used; - int state; -}; - -static const char *METHODS_STR[] = -{ - "", - "GET", - "POST", - "HEAD", - "PUT", - "CONNECT", - "OPTIONS", - "DELETE", - "TRACE", - "PATCH" -}; - -static http_mt_t str_to_method(const char *str) -{ - int res; - for (res = METHOD_GET; res <= METHOD_PATCH; res++) - if (strcmp(METHODS_STR[res], str) == 0) - return (http_mt_t)res; - return METHOD_NONE; -} - -bool str2hex(const char *str, uint8_t *hex) -{ - int d; - - d = str[0]; - if (d >= 'a') d -= 32; /* to upper case */ - if (d >= '0' && d <= '9') - d -= '0'; else - if (d >= 'A' && d <= 'F') - d += 10 - 'A'; else - return false; - *hex = d << 4; - - d = str[1]; - if (d >= 'a') d -= 32; /* to upper case */ - if (d >= '0' && d <= '9') - d -= '0'; else - if (d >= 'A' && d <= 'F') - d += 10 - 'A'; else - return false; - *hex |= d; - - return true; -} - -int http_unescape(char *str, int len, int null) -{ - int res = 0; - char *c = str; - (void)len; - while (*c != 0 && len > 0) - { - if (*c == '%' && len > 2) - { - uint8_t hex; - if (str2hex(c + 1, &hex)) - { - *str = hex; - str++; - res++; - c += 3; - len -= 3; - continue; - } - } - *str = *c == '+' ? ' ' : *c; - str++; - res++; - c++; - len--; - } - if (null) *str = 0; - return res; -} - -static http_ct_t str_to_ct(const char *str) -{ - if (strcmp(str, "close") == 0) return CT_CLOSE; - if (strcmp(str, "keep-alive") == 0) return CT_KEEP_ALIVE; - return CT_NONE; -} - -static void httpi_acc_field_setter(httpi_t *httpi, int arg); -static void httpi_str_field_setter(httpi_t *httpi, int arg); -static void httpi_ct_field_setter(httpi_t *httpi, int arg); -static void httpi_cntt_field_setter(httpi_t *httpi, int arg); -static void httpi_int_field_setter(httpi_t *httpi, int arg); -static void httpi_post_cdh_setter(httpi_t *httpi, int arg); - -#define OFFSET_REQ offsetof(httpi_t, req) -#define OFFSET_FLD(name) offsetof(http_req_t, name) -#define OFFSET_CONT_FLD(name) offsetof(http_cont_t, name) -#define OFFSET_POST offsetof(httpi_t, post) -#define OFFSET_POST_FLD(name) offsetof(http_post_t, name) - -struct field_info -{ - const char *name; - int offset; - void (*setter)(httpi_t *httpi, int arg); - int composite; -}; - -struct field_info hdr_fields[] = -{ - /* hdr field name */ - { "Accept", OFFSET_REQ + OFFSET_FLD(accept), httpi_acc_field_setter, 1 }, - { "Accept-Charset", OFFSET_REQ + OFFSET_FLD(accept_charset), httpi_str_field_setter, 0 }, - { "Accept-Encoding", OFFSET_REQ + OFFSET_FLD(accept_encoding), httpi_str_field_setter, 0 }, - { "Accept-Language", OFFSET_REQ + OFFSET_FLD(accept_language), httpi_str_field_setter, 0 }, - { "Authorization", OFFSET_REQ + OFFSET_FLD(authorization), httpi_str_field_setter, 0 }, - { "Connection", OFFSET_REQ + OFFSET_FLD(connection), httpi_ct_field_setter, 0 }, - { "Expect", OFFSET_REQ + OFFSET_FLD(expect), httpi_str_field_setter, 0 }, - { "From", OFFSET_REQ + OFFSET_FLD(from), httpi_str_field_setter, 0 }, - { "Host", OFFSET_REQ + OFFSET_FLD(host), httpi_str_field_setter, 0 }, - { "If-Match", OFFSET_REQ + OFFSET_FLD(if_match), httpi_str_field_setter, 0 }, - { "If-Modified-Since", OFFSET_REQ + OFFSET_FLD(if_modified_since), httpi_str_field_setter, 0 }, - { "If-None-Match", OFFSET_REQ + OFFSET_FLD(if_none_match), httpi_str_field_setter, 0 }, - { "If-Range", OFFSET_REQ + OFFSET_FLD(if_range), httpi_str_field_setter, 0 }, - { "If-Unmodified-Since", OFFSET_REQ + OFFSET_FLD(if_unmodified_since), httpi_str_field_setter, 0 }, - { "Max-Forwards", OFFSET_REQ + OFFSET_FLD(max_forwards), httpi_int_field_setter, 0 }, - { "Proxy-Authorization", OFFSET_REQ + OFFSET_FLD(proxy_authorization), httpi_str_field_setter, 0 }, - { "Referer", OFFSET_REQ + OFFSET_FLD(referer), httpi_str_field_setter, 0 }, - { "TE", OFFSET_REQ + OFFSET_FLD(te), httpi_str_field_setter, 0 }, - { "User-Agent", OFFSET_REQ + OFFSET_FLD(user_agent), httpi_str_field_setter, 0 }, - { "Cookie", OFFSET_REQ + OFFSET_FLD(cookie), httpi_str_field_setter, 0 }, - { "Keep-Alive", OFFSET_REQ + OFFSET_FLD(keep_alive), httpi_int_field_setter, 0 }, - { "Content-Type", OFFSET_REQ + OFFSET_FLD(content), httpi_cntt_field_setter, 1 }, - { "Content-Encoding", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(encoding), httpi_str_field_setter, 0 }, - { "Content-Language", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(language), httpi_str_field_setter, 0 }, - { "Content-Length", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(length), httpi_int_field_setter, 0 }, - { "Content-Location", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(location), httpi_str_field_setter, 0 }, - { "Content-MD5", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(md5), httpi_str_field_setter, 0 }, - { "Content-Version", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(ver), httpi_str_field_setter, 0 }, - { "Expires", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(expires), httpi_str_field_setter, 0 }, - { "Last-Modified", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(modified), httpi_str_field_setter, 0 }, - { "Link", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(link), httpi_str_field_setter, 0 }, - { "Title", OFFSET_REQ + OFFSET_FLD(content) + OFFSET_CONT_FLD(title), httpi_str_field_setter, 0 }, - { NULL } -}; - -struct field_info mpart_fields[] = -{ - { "Content-Type", OFFSET_POST + OFFSET_POST_FLD(content_type), httpi_str_field_setter, 1 }, - { "Content-Disposition", OFFSET_POST, httpi_post_cdh_setter, 1 }, - { NULL } -}; - -int httpi_readlex(httpi_t *httpi, int *stack, const char *stop, int skipstop, int cntlim) -{ - while (true) - { - char c; - if (httpi->in.pos == httpi->in.size) return CODE_IN_EOF; - c = httpi->in.data[httpi->in.pos]; - if (httpi->out.pos >= httpi->out.size - 1) return CODE_OUT_EOF; - if (c == stop[0] || c == stop[1] || c == stop[2] || c == stop[3]) - { - if (skipstop) httpi->in.pos++; - httpi->out.data[httpi->out.pos] = 0; - stack[1] = c; - return CODE_DONE; - } - httpi->out.data[httpi->out.pos] = c; - httpi->out.pos++; - httpi->in.pos++; - httpi->in.tot++; - *stack += 1; - if (*stack == cntlim) return CODE_CNT_LIM; - } -} - -int httpi_skip_char(httpi_t *httpi, int char1, int char2) -{ - char c; - if (httpi->in.pos == httpi->in.size) return CODE_IN_EOF; - c = httpi->in.data[httpi->in.pos]; - if (c != char1 && c != char2) return CODE_ERROR; - httpi->in.pos++; - httpi->in.tot++; - return CODE_DONE; -} - -static inline void httpi_inc_used(httpi_t *httpi, int size) -{ - httpi->pool.used += size; - httpi->out.data = httpi->pool.data + httpi->pool.used; - httpi->out.size = httpi->pool.size - httpi->pool.used; - httpi->out.pos = 0; -} - -static inline void httpi_set_used(httpi_t *httpi, int used) -{ - httpi->pool.used = used; - httpi->out.data = httpi->pool.data + httpi->pool.used; - httpi->out.size = httpi->pool.size - httpi->pool.used; - httpi->out.pos = 0; -} - -#define FIELD ((char *)httpi + httpi->rqhdr.field->offset) - -static void httpi_str_field_setter(httpi_t *httpi, int arg) -{ - *(const char **)FIELD = httpi->out.data; - httpi_inc_used(httpi, http_unescape(httpi->out.data, httpi->out.pos, 1) + 1); -} - -static void httpi_int_field_setter(httpi_t *httpi, int arg) -{ - *(int *)FIELD = strtol(httpi->out.data, NULL, 10); - httpi->out.pos = 0; -} - -static void httpi_ct_field_setter(httpi_t *httpi, int arg) -{ - *(http_ct_t *)FIELD = str_to_ct(httpi->out.data); - httpi->out.pos = 0; -} - -static void httpi_acc_field_setter(httpi_t *httpi, int arg) -{ - httpaccept_t *acc = (httpaccept_t *)FIELD; - /* text/html,application/xhtml+xml,application/xml;q=0.9,*;q=0.8 */ - if (acc->count >= HTTP_REQ_MAX_ACCEPT) return; - switch (httpi->setter.state) - { - case 0: /* wait type name */ - acc->type[acc->count] = httpi->out.data; - acc->q[acc->count] = 1; - acc->count++; - httpi_inc_used(httpi, http_unescape(httpi->out.data, httpi->out.pos, 1) + 1); - if (arg == ';') httpi->setter.state = 1; - break; - case 1: /* wait param name */ - httpi->out.pos = 0; - if (arg != '=') - { - httpi->setter.state = 0; - break; - } - if (strcmp(httpi->out.data, "level") == 0) - httpi->setter.state = 2; - else - if (strcmp(httpi->out.data, "q") == 0) - httpi->setter.state = 3; - break; - case 2: /* wait level value */ - acc->level[acc->count - 1] = strtol(httpi->out.data, NULL, 10); - if (arg == ',') - httpi->setter.state = 1; else - httpi->setter.state = 0; - httpi->out.pos = 0; - break; - case 3: /* wait q value */ - acc->q[acc->count - 1] = strtof(httpi->out.data, NULL); - if (arg == ';') - httpi->setter.state = 1; else - httpi->setter.state = 0; - httpi->out.pos = 0; - break; - } -} - -static void httpi_cntt_field_setter(httpi_t *httpi, int arg) -{ - http_cont_t *cont = (http_cont_t *)FIELD; - /* multipart/form-data; boundary=Asrf456BGe4h */ - switch (httpi->setter.state) - { - case 0: /* wait type name */ - cont->type = httpi->out.data; - httpi_inc_used(httpi, http_unescape(httpi->out.data, httpi->out.pos, 1) + 1); - if (arg == ';') - httpi->setter.state = 1; else - httpi->setter.state = 10; - break; - case 1: /* wait param name */ - httpi->out.pos = 0; - if (arg != '=') - { - httpi->setter.state = 10; - break; - } - if (strcmp(httpi->out.data, "boundary") == 0) - { - httpi->out.data[0] = '\r'; - httpi->out.data[1] = '\n'; - httpi->out.data[2] = '-'; - httpi->out.data[3] = '-'; - httpi->mpart.bndry = httpi->out.data + 2; - httpi->mpart.bndry_size = 2; - httpi_inc_used(httpi, 4); - httpi->setter.state = 2; - } - else - httpi->setter.state = 10; - break; - case 2: /* boundary */ - httpi->mpart.bndry_size += httpi->out.pos; - cont->boundary = httpi->out.data; - httpi_inc_used(httpi, httpi->out.pos + 1); - httpi->setter.state = 10; - break; - case 10: - break; - } -} - -static void httpi_post_cdh_setter(httpi_t *httpi, int arg) -{ - http_post_t *post = (http_post_t *)FIELD; - /* form-data; name="AttachedFile1"; filename="photo-1.jpg" */ - switch (httpi->setter.state) - { - case 0: /* wait type name */ - post->disp_type = httpi->out.data; - httpi_inc_used(httpi, http_unescape(httpi->out.data, httpi->out.pos, 1) + 1); - if (arg == ';') - httpi->setter.state = 1; else - httpi->setter.state = 10; - break; - case 1: /* wait param name */ - httpi->out.pos = 0; - httpi->setter.state = 10; - if (arg != '=') break; - if (strcmp(httpi->out.data, "name") == 0) - httpi->setter.state = 2; else - if (strcmp(httpi->out.data, "filename") == 0) - httpi->setter.state = 3; - break; - case 2: /* wait name */ - if (arg == ',') - httpi->setter.state = 0; else - httpi->setter.state = 1; - post->name = httpi->out.data; - httpi_inc_used(httpi, http_unescape(httpi->out.data, httpi->out.pos, 1) + 1); - break; - case 3: /* wait filename */ - if (arg == ',') - httpi->setter.state = 0; else - httpi->setter.state = 1; - post->file = httpi->out.data; - httpi_inc_used(httpi, http_unescape(httpi->out.data, httpi->out.pos, 1) + 1); - break; - case 10: - break; - } -} - -#undef FIELD - -int httpi_lex_reader(httpi_t *httpi, const char *stop, int skipstop, int cntlim) -{ - while (true) - { - char c; - if (httpi->out.pos >= httpi->out.size - 1) return CODE_OUT_EOF; - if (httpi->in.tot == cntlim && cntlim >= 0) - { - httpi->out.data[httpi->out.pos] = 0; - return CODE_CNT_LIM; - } - if (httpi->in.pos == httpi->in.size) return CODE_IN_EOF; - c = httpi->in.data[httpi->in.pos]; - if (c == stop[0] || c == stop[1] || c == stop[2] || c == stop[3]) - { - if (skipstop) - { - httpi->in.pos++; - httpi->in.tot++; - } - httpi->out.data[httpi->out.pos] = 0; - httpi->lexrd.stop = c; - return CODE_DONE; - } - httpi->out.data[httpi->out.pos] = c; - httpi->out.pos++; - httpi->in.pos++; - httpi->in.tot++; - } -} - -int httpi_rqline(httpi_t *httpi) -{ - int code; -start: - switch (httpi->rqline.state) - { - case STATE_RQLINE_METHOD: - code = httpi_lex_reader(httpi, "\r \0\0", 1, -1); - if (code != CODE_DONE) return code; - if (httpi->lexrd.stop == '\r') return CODE_ERROR; - httpi->req.method = str_to_method(httpi->out.data); - httpi->out.pos = 0; - httpi->rqline.state = STATE_RQLINE_URI; - goto start; - case STATE_RQLINE_URI: - code = httpi_lex_reader(httpi, "\r ?\0", 1, -1); - if (code != CODE_DONE) return code; - if (httpi->lexrd.stop == '\r') return CODE_ERROR; - if (httpi->lexrd.stop == '?') - httpi->rqline.state = STATE_RQLINE_KEY; else - httpi->rqline.state = STATE_RQLINE_VER; - httpi->req.uri = httpi->out.data; - httpi_inc_used(httpi, http_unescape(httpi->out.data, httpi->out.pos, 1) + 1); - goto start; - case STATE_RQLINE_KEY: - case STATE_RQLINE_VAL: - code = httpi_lex_reader(httpi, "\r &=", 1, -1); - if (code != CODE_DONE) return code; - if (httpi->req.nparams >= HTTP_REQ_MAX_PARAMS) return CODE_MEM_ERROR; - if (httpi->rqline.state == STATE_RQLINE_KEY) - { - httpi->req.params[httpi->req.nparams] = httpi->out.data; - httpi->req.values[httpi->req.nparams] = NULL; - httpi->req.nparams++; - } - else - { - httpi->req.values[httpi->req.nparams - 1] = httpi->out.data; - } - httpi_inc_used(httpi, http_unescape(httpi->out.data, httpi->out.pos, 1) + 1); - switch (httpi->lexrd.stop) - { - case ' ': httpi->rqline.state = STATE_RQLINE_VER; break; - case '&': httpi->rqline.state = STATE_RQLINE_KEY; break; - case '=': httpi->rqline.state = STATE_RQLINE_VAL; break; - case '\r': return CODE_ERROR; - } - goto start; - case STATE_RQLINE_VER: - code = httpi_lex_reader(httpi, "\r\0\0\0", 1, -1); - if (code != CODE_DONE) return code; - httpi->req.ver = httpi->out.data; - httpi_inc_used(httpi, http_unescape(httpi->out.data, httpi->out.pos, 1) + 1); - httpi->rqline.state = STATE_RQLINE_SKIPN; - goto start; - case STATE_RQLINE_SKIPN: - code = httpi_skip_char(httpi, '\n', '\0'); - return code; - default: - return CODE_ERROR; - } -} - -const fld_t *find_field(const fld_t *fields, const char *name) -{ - int i; - char c = name[0]; - for (i = 0; fields[i].name != NULL; i++) - if (c == fields[i].name[0]) - if (strcmp(fields[i].name, name) == 0) - return fields + i; - return NULL; -} - -int httpi_hdr_reader(httpi_t *httpi, int composite_val) -{ - int code; -start: - switch (httpi->hdrrd.state) - { - case STATE_HDRRD_INIT: - httpi->hdrrd.state = STATE_HDRRD_KEYRD; - httpi->out.pos = 0; - goto start; - case STATE_HDRRD_KEYRD: - code = httpi_lex_reader(httpi, "\r:\0\0", 1, -1); - if (code != CODE_DONE) return code; - if (httpi->lexrd.stop == '\r') - { - if (httpi->out.pos != 0) return CODE_ERROR; - httpi->hdrrd.state = STATE_HDRRD_LASTN; - goto start; - } - httpi->hdrrd.state = STATE_HDRRD_KEY; - return CODE_DONE; - case STATE_HDRRD_KEY: - httpi->hdrrd.state = composite_val ? STATE_HDRRD_CSKIPWS : STATE_HDRRD_SKIPWS; - goto start; - case STATE_HDRRD_FINISHED: - return CODE_DONE; - case STATE_HDRRD_SKIPWS: - case STATE_HDRRD_CSKIPWS: - if (httpi->in.pos >= httpi->in.size) return CODE_IN_EOF; - if (httpi->in.data[httpi->in.pos] == ' ') - { - httpi->in.pos++; - httpi->in.tot++; - goto start; - } - httpi->hdrrd.state++; - goto start; - case STATE_HDRRD_VALRD: - code = httpi_lex_reader(httpi, "\r\0\0\0", 1, -1); - if (code != CODE_DONE) return code; - httpi->hdrrd.state = STATE_HDRRD_VAL; - return CODE_DONE; - case STATE_HDRRD_CVALRD: - code = httpi_lex_reader(httpi, "\r;,=", 1, -1); - if (code != CODE_DONE) return code; - httpi->hdrrd.state = STATE_HDRRD_CVAL; - return CODE_DONE; - case STATE_HDRRD_VAL: - httpi->hdrrd.state = STATE_HDRRD_SKIPN; - goto start; - case STATE_HDRRD_CVAL: - httpi->hdrrd.state = httpi->lexrd.stop == '\r' ? - STATE_HDRRD_SKIPN : STATE_HDRRD_CSKIPWS; - goto start; - case STATE_HDRRD_SKIPN: - case STATE_HDRRD_LASTN: - if (httpi->in.pos >= httpi->in.size) return CODE_IN_EOF; - if (httpi->in.data[httpi->in.pos] != '\n') return CODE_ERROR; - httpi->in.pos++; - httpi->in.tot++; - httpi->hdrrd.state = httpi->hdrrd.state == STATE_HDRRD_LASTN ? - STATE_HDRRD_FINISHED : STATE_HDRRD_KEYRD; - goto start; - default: - return CODE_ERROR; - } -} - -int httpi_request_hdr_reader(httpi_t *httpi, const fld_t *fields) -{ - int code; -start: - switch (httpi->rqhdr.state) - { - case 0: /* initial */ - httpi->rqhdr.field = NULL; - httpi->rqhdr.state = 1; - httpi->hdrrd.state = 0; - case 1: /* wait key */ - code = httpi_hdr_reader(httpi, 0); - if (code != CODE_DONE) return code; - if (httpi->hdrrd.state == STATE_HDRRD_FINISHED) return CODE_DONE; - httpi->rqhdr.field = find_field(fields, httpi->out.data); - httpi->out.pos = 0; - httpi->setter.state = 0; - httpi->rqhdr.state = 2; - case 2: /* read value or composite value */ - code = 0; - if (httpi->rqhdr.field != NULL) - code = httpi->rqhdr.field->composite; - code = httpi_hdr_reader(httpi, code); - if (code != CODE_DONE) return code; - if (httpi->rqhdr.field != NULL) - httpi->rqhdr.field->setter(httpi, httpi->lexrd.stop); else - httpi->out.pos = 0; - httpi->rqhdr.state = httpi->lexrd.stop == '\r' ? 1 : 2; - goto start; - } - return CODE_ERROR; -} - -#define MPART_STATE httpi->mpart.state -#define MPART_CNTR httpi->mpart.bndry_cntr -#define MPART_POS httpi->mpart.bndry_pos - -int httpi_mpart(httpi_t *httpi) -{ - int avail; - avail = httpi->out.size - httpi->out.pos; - if (avail <= 1) return CODE_OUT_EOF; - -start: - switch (MPART_STATE) - { - case STATE_MPART_DATARD: - while (true) - { - char c; - if (httpi->in.pos >= httpi->in.size) return CODE_IN_EOF; - c = httpi->in.data[httpi->in.pos]; - if (httpi->mpart.bndry[MPART_CNTR] == c) - { - httpi->in.pos++; - httpi->in.tot++; - MPART_CNTR++; - if (MPART_CNTR != httpi->mpart.bndry_size) continue; - MPART_CNTR = 0; - MPART_STATE = STATE_MPART_ENDCHECK; - goto start; - } - /* not a boundary */ - if (MPART_CNTR > 0) - { - MPART_POS = 0; - MPART_STATE = STATE_MPART_NOTBNDRY; - goto start; - } - if (httpi->out.pos >= httpi->out.size - 1) - { - httpi->out.data[httpi->out.pos] = 0; - return CODE_OUT_EOF; - } - httpi->out.data[httpi->out.pos] = c; - httpi->out.pos++; - httpi->in.pos++; - httpi->in.tot++; - } - case STATE_MPART_NOTBNDRY: - while (true) - { - if (httpi->out.pos >= httpi->out.size - 1) - { - httpi->out.data[httpi->out.pos] = 0; - return CODE_OUT_EOF; - } - httpi->out.data[httpi->out.pos] = httpi->mpart.bndry[MPART_POS]; - MPART_POS++; - httpi->out.pos++; - MPART_CNTR--; - if (MPART_CNTR != 0) continue; - MPART_STATE = STATE_MPART_DATARD; - goto start; - } - case STATE_MPART_ENDCHECK: /* skip '-' or '\r' */ - if (httpi->in.pos >= httpi->in.size) return CODE_IN_EOF; - switch (httpi->in.data[httpi->in.pos]) - { - case '\r': MPART_STATE = STATE_MPART_SKIPN; break; - case '-': MPART_STATE = STATE_MPART_SKIPMINUS; break; - default: return CODE_ERROR; - } - httpi->in.pos++; - httpi->in.tot++; - goto start; - case STATE_MPART_SKIPMINUS: /* skip '-' */ - if (httpi->in.pos >= httpi->in.size) return CODE_IN_EOF; - if (httpi->in.data[httpi->in.pos] != '-') return CODE_ERROR; - MPART_STATE = STATE_MPART_SKIPR; - httpi->in.pos++; - httpi->in.tot++; - goto start; - case STATE_MPART_SKIPR: /* skip 'r' */ - if (httpi->in.pos >= httpi->in.size) return CODE_IN_EOF; - if (httpi->in.data[httpi->in.pos] != '\r') return CODE_ERROR; - MPART_STATE = STATE_MPART_LASTN; - httpi->in.pos++; - httpi->in.tot++; - goto start; - case STATE_MPART_LASTN: - case STATE_MPART_SKIPN: /* skip 'n' */ - if (httpi->in.pos >= httpi->in.size) return CODE_IN_EOF; - if (httpi->in.data[httpi->in.pos] != '\n') return CODE_ERROR; - httpi->in.pos++; - httpi->in.tot++; - MPART_STATE = MPART_STATE == STATE_MPART_LASTN ? - STATE_MPART_FINISHED : STATE_MPART_BNDRY; - return CODE_DONE; - case STATE_MPART_BNDRY: - MPART_STATE = STATE_MPART_DATARD; - goto start; - default: - return CODE_ERROR; - } -} - -/* -returns: - CODE_DONE - in states: - STATE_URLENC_KEY - key readed - STATE_URLENC_CHUNK - value chunk readed - STATE_URLENC_END - value readed - STATE_URLENC_FINISHED - all done - CODE_IN_EOF - in any state - not an error - CODE_MEM_ERROR - no memory in pool -*/ - -int httpi_urlenc(httpi_t *httpi) -{ - char c; - int code; -start: - switch (httpi->urlenc.state) - { - case STATE_URLENC_INIT: - httpi->in.tot = 0; - httpi->out.pos = 0; - httpi->urlenc.state = STATE_URLENC_KEYRD; - httpi->used = httpi->pool.used; - case STATE_URLENC_KEYRD: - code = httpi_lex_reader(httpi, "=&\0\0", 0, httpi->req.content.length); - switch (code) - { - case CODE_OUT_EOF: - return CODE_MEM_ERROR; - case CODE_CNT_LIM: - if (httpi->out.pos <= 0) - { - httpi->urlenc.state = STATE_URLENC_END; - return CODE_DONE; - } - case CODE_DONE: - httpi->out.pos = http_unescape(httpi->out.data, httpi->out.pos, 1); - httpi->urlenc.state = STATE_URLENC_KEY; - return CODE_DONE; - default: - return code; - } - case STATE_URLENC_KEY: - if (httpi->in.tot >= httpi->req.content.length) /* CODE_CNT_LIM! */ - goto return_empty_val; - c = httpi->in.data[httpi->in.pos]; - httpi->in.pos++; - httpi->in.tot++; - if (c == '&') goto return_empty_val; - /* read value now! */ - httpi->urlenc.state = STATE_URLENC_VALRD; - httpi->out.pos = 0; - case STATE_URLENC_VALRD: - code = httpi_lex_reader(httpi, "&\0\0\0", 0, httpi->req.content.length); - switch (code) - { - case CODE_OUT_EOF: - if (httpi->out.pos < 2) return CODE_MEM_ERROR; - *(uint32_t *)httpi->urlenc.extra = 0; - if (httpi->out.data[httpi->out.pos - 1] == '%') - { - httpi->urlenc.extra[0] = '%'; - httpi->out.pos--; - } - else - { - if (httpi->out.data[httpi->out.pos - 2] == '%') - { - httpi->urlenc.extra[0] = '%'; - httpi->urlenc.extra[1] = httpi->out.data[httpi->out.pos - 1]; - httpi->out.pos -= 2; - } - } - httpi->out.pos = http_unescape(httpi->out.data, httpi->out.pos, 1); - httpi->urlenc.state = STATE_URLENC_CHUNK; - return CODE_DONE; - case CODE_DONE: /* & */ - httpi->in.pos++; - httpi->in.tot++; - case CODE_CNT_LIM: - httpi->out.pos = http_unescape(httpi->out.data, httpi->out.pos, 1); - httpi->urlenc.state = STATE_URLENC_END; - return CODE_DONE; - default: - return code; - } - case STATE_URLENC_CHUNK: - for (httpi->out.pos = 0; httpi->urlenc.extra[httpi->out.pos] != 0; httpi->out.pos++) - httpi->out.data[httpi->out.pos] = httpi->urlenc.extra[httpi->out.pos]; - httpi->urlenc.state = STATE_URLENC_VALRD; - goto start; - case STATE_URLENC_END: - httpi_set_used(httpi, httpi->used); - if (httpi->in.tot >= httpi->req.content.length) /* CODE_CNT_LIM! */ - httpi->urlenc.state = STATE_URLENC_FINISHED; else - httpi->urlenc.state = STATE_URLENC_KEYRD; - goto start; - case STATE_URLENC_FINISHED: - return CODE_DONE; - } - return CODE_ERROR; /* paranoya */ - -return_empty_val: - if (httpi->in.pos >= httpi->in.size) return CODE_MEM_ERROR; - httpi->out.data[httpi->out.pos] = 0; - httpi->out.pos = 0; - httpi->urlenc.state = STATE_URLENC_END; - return CODE_DONE; -} - -static void httpi_reset(httpi_t *httpi) -{ - memset(&httpi->req, 0, sizeof(http_req_t)); - memset(&httpi->post, 0, sizeof(http_post_t)); - httpi->pool.used = 0; - httpi->in.tot = 0; - httpi->out.data = httpi->pool.data; - httpi->out.size = httpi->pool.size; - httpi->out.pos = 0; - httpi->state = 0; - httpi->rqline.state = 0; -} - -httpi_t *httpi_init(const void *pool, int size) -{ - httpi_t *httpi; - if (size - (int)sizeof(httpi_t) < 64) return NULL; - httpi = (httpi_t *)(((size_t)pool + size - sizeof(httpi_t)) & ~(MEM_ALIGNMENT - 1)); - memset(httpi, 0, sizeof(httpi_t)); - httpi->pool.data = (char *)pool; - httpi->pool.size = (char *)httpi - (char *)pool; - httpi->pool.used = 0; - httpi->in.data = NULL; - httpi->in.pos = 0; - httpi->in.tot = 0; - httpi->in.size = 0; - httpi_reset(httpi); - return httpi; -} - -void httpi_push(httpi_t *httpi, const void *data, int size) -{ - httpi->in.data = (char *)data; - httpi->in.size = size; - httpi->in.pos = 0; -} - -void httpi_get_state(httpi_t *httpi, char **pool, int *avail) -{ - *pool = httpi->pool.data + httpi->pool.used + httpi->out.pos + 1; - *avail = httpi->pool.size - httpi->pool.used - httpi->out.pos - 1; - if (*avail < 0) *avail = 0; -} - -const http_req_t *httpi_request(httpi_t *httpi) -{ - return httpi->state > STATE0_RQHDR ? &httpi->req : NULL; -} - -const http_post_t *httpi_posted(httpi_t *httpi) -{ - return httpi->post.name == NULL ? NULL : &httpi->post; -} - -#define ERROR(code) \ - { \ - httpi->state = STATE0_ERROR; \ - return code; \ - } - -int httpi_pull(httpi_t *httpi) -{ - httpi->post.first = 0; -start: - switch (httpi->state) - { - case STATE0_RQLINE: - switch (httpi_rqline(httpi)) - { - case CODE_IN_EOF: return HTTP_IN_NODATA; - case CODE_OUT_EOF: ERROR(HTTP_IN_ERR_NOMEM); - case CODE_ERROR: ERROR(HTTP_IN_ERR_SYNT); - case CODE_DONE: - httpi->state = STATE0_RQHDR; - httpi->rqhdr.state = 0; - goto start; - } - case STATE0_RQHDR: - switch (httpi_request_hdr_reader(httpi, hdr_fields)) - { - case CODE_IN_EOF: return HTTP_IN_NODATA; - case CODE_OUT_EOF: ERROR(HTTP_IN_ERR_NOMEM); - case CODE_ERROR: ERROR(HTTP_IN_ERR_SYNT); - case CODE_DONE: - httpi->state = STATE0_DONE; - if (httpi->req.content.type != NULL) - { - if (strcmp(httpi->req.content.type, MIME_URLENCODED) == 0) - { - httpi->state = STATE0_URLENC; - httpi->urlenc.state = 0; - memset(&httpi->post, 0, sizeof(http_post_t)); - } - else - if (strcmp(httpi->req.content.type, MIME_MPART_FORM) == 0) - { - if (httpi->req.content.boundary == NULL) ERROR(HTTP_IN_ERR_SYNT); - if (*httpi->req.content.boundary == 0) ERROR(HTTP_IN_ERR_SYNT); - memset(&httpi->post, 0, sizeof(http_post_t)); - httpi->state = STATE0_MPART_DATA; - httpi->mpart.state = 0; - httpi->mpart.bndry_cntr = 0; - httpi->mpart.bndry_pos = 0; - httpi->used = httpi->pool.used; - } - } - return HTTP_IN_REQUEST; - } - case STATE0_URLENC: - switch (httpi_urlenc(httpi)) - { - case CODE_IN_EOF: return HTTP_IN_NODATA; - case CODE_ERROR: ERROR(HTTP_IN_ERR_SYNT); - case CODE_DONE: - switch (httpi->urlenc.state) - { - case STATE_URLENC_KEY: - memset(&httpi->post, 0, sizeof(http_post_t)); - httpi->post.name = httpi->out.data; - httpi->post.first = 1; - httpi_inc_used(httpi, httpi->out.pos + 1); - goto start; - case STATE_URLENC_END: - httpi->post.last = 1; - case STATE_URLENC_CHUNK: - httpi->post.data = httpi->out.data; - httpi->post.size = httpi->out.pos; - return HTTP_IN_POSTDATA; - case STATE_URLENC_FINISHED: - httpi->state = STATE0_DONE; - goto start; - } - default: /* not possible */ - ERROR(HTTP_IN_ERR_SYNT); - } - - case STATE0_MPART_DATA: - switch (httpi_mpart(httpi)) - { - case CODE_IN_EOF: return HTTP_IN_NODATA; - case CODE_ERROR: ERROR(HTTP_IN_ERR_SYNT); - case CODE_OUT_EOF: - if (httpi->out.pos <= 0) - ERROR(HTTP_IN_ERR_NOMEM); - if (httpi->post.name == NULL) - ERROR(HTTP_IN_ERR_SYNT); - httpi->post.data = httpi->out.data; - httpi->post.size = httpi->out.pos; - httpi->post.last = 0; - httpi->out.pos = 0; - return HTTP_IN_POSTDATA; - case CODE_DONE: - switch (httpi->mpart.state) - { - case STATE_MPART_FINISHED: httpi->state = STATE0_DONE; break; - case STATE_MPART_BNDRY: httpi->state = STATE0_MPART_INIT; break; - } - if (*httpi->mpart.bndry == '-') - { - httpi->mpart.bndry_size += 2; - httpi->mpart.bndry -= 2; - } - if (httpi->post.name == NULL && httpi->out.pos > 0) - ERROR(HTTP_IN_ERR_SYNT); - if (httpi->post.name == NULL) goto start; - httpi->post.data = httpi->out.data; - httpi->post.size = httpi->out.pos; - httpi->post.last = 1; - httpi->out.pos = 0; - return HTTP_IN_POSTDATA; - } - - case STATE0_MPART_INIT: - memset(&httpi->post, 0, sizeof(http_post_t)); - httpi->post.first = 1; - httpi->state = STATE0_MPART_HDR; - httpi->rqhdr.state = 0; - httpi->pool.used = httpi->used; - httpi->out.data = httpi->pool.data; - httpi->out.size = httpi->pool.size - httpi->pool.used; - httpi->out.pos = 0; - - case STATE0_MPART_HDR: - switch (httpi_request_hdr_reader(httpi, mpart_fields)) - { - case CODE_IN_EOF: return HTTP_IN_NODATA; - case CODE_OUT_EOF: ERROR(HTTP_IN_ERR_NOMEM); - case CODE_ERROR: ERROR(HTTP_IN_ERR_SYNT); - case CODE_DONE: - httpi->state = STATE0_MPART_DATA; - httpi->mpart.state = STATE_MPART_DATARD; - goto start; - } - - case STATE0_DONE: - httpi->state = STATE0_RESET; - return HTTP_IN_FINISHED; - - case STATE0_RESET: - httpi_reset(httpi); - goto start; - - default: - ERROR(HTTP_IN_ERR_SYNT); - } - -} -#undef ERROR - -#define MIN_OUTPUT_SIZE 256 -/* bytes: 8*hex + 2*crlf + (DATA) + 2*crlf; space to ending: 1*'0' + 2*crlf + 2*crlf */ -#define CHUNKED_RESERVE 17 -#define OUT_FLAG_CHUNKED 1 -#define OUT_FLAG_FINISHED 2 - -struct http_output -{ - char *buff; - int buffsz; - int outpos; - int outsz; - int flags; -}; - -#define ALIGNED(addr) (((size_t)addr + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT - 1)) - -static int write_str(httpo_t *out, const char *str) -{ - while (*str != 0) - { - if (out->outsz == out->buffsz) return 0; - out->buff[(out->outpos + out->outsz) % out->buffsz] = *str; - out->outsz++; - str++; - } - return 1; -} - -static inline int write_uint(httpo_t *out, uint32_t value, int radix) -{ - char s[16]; - sprintf(s, radix == 16 ? "%X" : "%u", value); - return write_str(out, s); -} - -static const char *CONN_TYPE_STR[] = -{ - "", "close", "keep-alive" -}; - -httpo_t *httpo_init(void *pool, int poolsz) -{ - httpo_t *res; - char *apool = (char *)ALIGNED(pool); - poolsz -= (apool - (char *)pool); - poolsz -= sizeof(struct http_output); - if (poolsz < MIN_OUTPUT_SIZE) return NULL; - res = (httpo_t *)apool; - res->buff = apool + sizeof(struct http_output); - res->buffsz = poolsz; - res->outpos = 0; - res->outsz = 0; - res->flags = 0; - return res; -} - -void httpo_state(httpo_t *out, char **data, int *size) -{ - *data = out->buff + out->outpos; - *size = out->buffsz - out->outpos; - if (*size > out->outsz) *size = out->outsz; -} - -void httpo_sended(httpo_t *out, int count) -{ - out->outpos = (out->outpos + count) % out->buffsz; - out->outsz -= count; -} - -int httpo_write_resp(httpo_t *out, const http_resp_t *resp) -{ - int done; - int outsz; - -#define PRNS(s) done &= write_str(out, s) -#define PRNU(v, r) done &= write_uint(out, v, r) -#define PRNH(s, var) { PRNS(s); PRNS(": "); PRNS(var); PRNS("\r\n"); } -#define PRNHU(s, var, r) { PRNS(s); PRNS(": "); PRNU(var, r); PRNS("\r\n"); } -#define PRNHS(s, var) { if (var != NULL) PRNH(s, var); } - - done = 1; - outsz = out->outsz; - PRNS("HTTP/1.1 "); PRNU(resp->code, 10); PRNS(" "); PRNS(http_code_str(resp->code)); PRNS("\r\n"); - PRNHS("Content-Encoding", resp->content.encoding); - PRNHS("Content-Language", resp->content.language); - if (resp->content.length >= 0) - PRNHU("Content-Length", resp->content.length, 10); - PRNHS("Content-Location", resp->content.location); - PRNHS("Content-MD5", resp->content.md5); - /* TODO: http_rng_t range; */ - PRNHS("Content-Type", resp->content.type); - PRNHS("Content-Version", resp->content.ver); - PRNHS("Expires", resp->content.expires); - PRNHS("Last-Modified", resp->content.modified); - PRNHS("Link", resp->content.link); - PRNHS("Title", resp->content.title); - PRNHS("Connection", CONN_TYPE_STR[resp->connection]); - PRNHS("Cache-Control", resp->cache_control); - PRNHS("ETag", resp->etag); - PRNHS("Location", resp->location); - PRNHS("Proxy-Authenticate", resp->proxy_authenticate); - PRNHS("Public", resp->Public); - if (resp->retry_after > 0) - PRNHU("Retry-After", resp->retry_after, 10); - PRNHS("Server", resp->server); - if (resp->transfer_encoding == TENC_CHUNKED) - PRNHS("Transfer-Encoding", "chunked"); - PRNHS("Vary", resp->vary); - PRNHS("WWW-Authenticate", resp->www_authenticate); - if (resp->exthdr != NULL) PRNS(resp->exthdr); - PRNS("\r\n"); - if (!done) - { - out->outsz = outsz; - return 0; - } - if (resp->transfer_encoding == TENC_CHUNKED) - out->flags |= OUT_FLAG_CHUNKED; - return 1; -} - -int httpo_write_avail(httpo_t *out) -{ - int size = out->buffsz - out->outsz; - if (out->flags & OUT_FLAG_CHUNKED) - size -= CHUNKED_RESERVE; - return size > 0 ? size : 0; -} - -const char hex_digits[] = "0123456789ABCDEF"; - -static inline void out_write(httpo_t *out, const void *mem, int size) -{ - int i; - for (i = 0; i < size; i++) - { - out->buff[(out->outpos + out->outsz) % out->buffsz] = ((const char *)mem)[i]; - out->outsz++; - } -} - -void write_chunk_size(httpo_t *out, uint32_t val) -{ - int i; - char buff[16]; - int len = 0; - for (i = 0; i < 8; i++) - { - int v = val >> 28; - if (len > 0 || v != 0) - buff[len++] = hex_digits[v]; - val = val << 4; - } - if (len == 0) - buff[len++] = '0'; - buff[len++] = '\r'; - buff[len++] = '\n'; - out_write(out, buff, len); -} - -int httpo_write_data(httpo_t *out, const void *data, int size) -{ - int avail; - if (size <= 0) return 0; - avail = out->buffsz - out->outsz; - if (out->flags & OUT_FLAG_CHUNKED) - { - avail -= CHUNKED_RESERVE; - if (avail <= 0) return 0; - if (size > avail) size = avail; - write_chunk_size(out, size); - out_write(out, data, size); - out_write(out, "\r\n", 2); - return size; - } - if (size > avail) size = avail; - out_write(out, data, size); - return size; -} - -void httpo_finished(httpo_t *out) -{ - out->flags |= OUT_FLAG_FINISHED; - if (out->flags & OUT_FLAG_CHUNKED) - out_write(out, "0\r\n\r\n", 5); -} - -#ifdef __cplusplus -} -#endif diff --git a/modules/web/http_server_simple/httpio/httpio.h b/modules/web/http_server_simple/httpio/httpio.h deleted file mode 100644 index a6cf56788..000000000 --- a/modules/web/http_server_simple/httpio/httpio.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 by Sergey Fetisov - * - * 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. - */ - -#ifndef HTTPIO_H -#define HTTPIO_H - -#include -#include -#include -#include -#include -#include -#include "http.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct http_output httpo_t; -typedef struct http_input httpi_t; -typedef struct http_post_info http_post_t; - -struct http_post_info -{ - const char *name; - const char *file; - const char *disp_type; - const char *content_type; - const char *data; /**< pointer to current post data chunk */ - int size; /**< size of current post data chunk */ - int first; /**< is it first post data chunk */ - int last; /**< is it last post data chunk */ -}; - -/* next codes returns httpi_pull function: */ -#define HTTP_IN_NODATA 0 /* have no more input data */ -#define HTTP_IN_REQUEST 2 /* http request parsed */ -#define HTTP_IN_POSTDATA 32 /* has POST-request data */ -#define HTTP_IN_FINISHED 64 /* request parsing is finished */ -#define HTTP_IN_ERR_SYNT 256 /* request syntax error */ -#define HTTP_IN_ERR_NOMEM 512 /* have no memory in pool */ -#define HTTP_IN_ERR_UMETH 1024 /* unknown request method */ -#define HTTP_IN_ERR_PARLIM 2048 /* too many request parameters */ - -/** - * @brief Initialize new http-input driver - * @param pool Memory pool buffer - * @param size Memory pool buffer size - * @return Http-input driver instance or NULL if \a size value is too small - * @warning You shouldn't change any data in pool after this call - * - * Instance structure will be allocated from a pool. - * Library has no any dynamic allocation call. - */ -httpi_t *httpi_init(const void *pool, int size); - -/** - * @brief Get the next parsed element - * @param httpi Http-input driver instance - * @return One of HTTP_IN_xxx value - */ -int httpi_pull(httpi_t *httpi); - -/** - * @brief Push the received data to a driver instance for it parsing - * @param httpi Http-input driver instance - * @param data Pointer to a data - * @param size Data size - * @warning You shouldn't change data until the httpi_pull() call not returns HTTP_IN_NODATA value - */ -void httpi_push(httpi_t *httpi, const void *data, int size); - -/** - * @brief Allows to know the pool buffer state - * @param httpi Http-input driver instance - * @param pool Output pointer to unused pool space - * @param avail Output value of unused pool space - * - * You can use the unused space to receive the data from a network - * before the httpi_push() call like this: - * int size; - * char *data; - * httpi_get_state(httpi, &pool, &size); - * size = recv(client, data, size, 0); - * httpi_push(httpi, data, size); - */ -void httpi_get_state(httpi_t *httpi, char **pool, int *avail); - -/** - * @brief Get the HTTP-request structure - * @param httpi Http-input driver instance - * @return Pointer to the request structure - * - * You can do this call if httpi_pull() returned HTTP_IN_REQUEST - */ -const http_req_t *httpi_request(httpi_t *httpi); - -/** - * @brief Get the next HTTP POST data - * @param httpi Http-input driver instance - * @return Pointer to the http_post_t structure - * - * You can do this call if httpi_pull() returned HTTP_IN_POSTDATA - */ -const http_post_t *httpi_posted(httpi_t *httpi); - -/** - * @brief Initialize the HTTP-output driver instance - * @param pool Memory pool buffer - * @param poolsz Memory pool buffer size - * @return HTTP-output driver instance - */ -httpo_t *httpo_init(void *pool, int poolsz); - -/** - * @brief Returns the prepared HTTP output data - * @param out HTTP-output driver instance - * @param data Output pointer to prepared data - * @param size Output value of prepared data size - */ -void httpo_state(httpo_t *out, char **data, int *size); - -/** - * @brief Increments the tail pointer of output buffer - * @param out HTTP-output driver instance - * @param count The amount of data that has been sent - */ -void httpo_sended(httpo_t *out, int count); - -/** - * @brief Writes the HTTP response to the output buffer - * @param out HTTP-output driver instance - * @param resp Responce structure - * @return 1 if successful, or 0 if not enough memory in the output buffer - */ -int httpo_write_resp(httpo_t *out, const http_resp_t *resp); - -/** - * @brief Writes the response data to the output buffer - * @param out HTTP-output driver instance - * @param data Response data - * @param size Response data size - * @return 1 if successful, or 0 if not enough memory in the output buffer - */ -int httpo_write_data(httpo_t *out, const void *data, int size); - -/** - * @brief Returns the size of the data available for writing by httpo_write_data - * @param out HTTP-output driver instance - * @return Size of the data available for writing - */ -int httpo_write_avail(httpo_t *out); - -/** - * @brief Correctly ends the output stream - * @param out HTTP-output driver instance - */ -void httpo_finished(httpo_t *out); - -#ifdef __cplusplus -} -#endif - -#endif