123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- //#define ENABLE_CORS_SUPER_FUN_TIME
- #include "http-server.h"
- #include "../server.h" //FIM_BUFFER_LEN
- uint16_t intLen(uint16_t i) {
- if(i >= 10000) return 5;
- if(i >= 1000) return 4;
- if(i >= 100) return 3;
- if(i >= 10) return 2;
- /*(i >= 1) */ return 1;
- }
- char * responseHeader(int docLen, int *outLen) {
- static char buf[2048];
- char dateBuf[2048], saved[2][2048], *fmt = TYPICAL_HEADER;
- time_t n;
- struct tm *t;
- // save the previous locale and timezone
- strcpy(saved[0], setlocale(LC_ALL, NULL)); strcpy(saved[1], tzname[0]);
- // update locale to "C" (English day/month names are required by HTTP)
- setlocale(LC_ALL, "C");
- // set the timezone to Greenwich Mean Time as per RFC7231 7.1.1.2
- setenv("TZ", "GMT", 1); tzset();
- // get the current time
- n = time(NULL);
- // split the time into parts (seconds, minutes, ..., day-in-the-year)
- t = gmtime(&n);
- /* copy the time into our buffer, using this format:
- * %a: abbreviated name of day
- * | ,: a comma
- * | | %d: day of month as decimal 01-31
- * | | | %b: abbreviated month name
- * | | | | %Y: Year as decimal includes century
- * | | | | | %H: 24-hour clock decimal 00-23
- * | | | | | |
- * Date: Tue, 11 Aug 2020 15:29:59 GMT
- * | | |
- * minute decimal 00-59: %M | |
- * second decimal 00-59: %S |
- * timezone: %Z
- *
- * [!] all four white spaces are required, the total lenght should always
- * be exactly 29 characters long
- */
- strftime(dateBuf, sizeof(dateBuf), "%a, %d %b %Y %H:%M:%S %Z", t);
- // generate a warning message when we goof up the Date header
- if(RFC7231_DATE_LENGTH != strlen(dateBuf))
- fprintf(stderr, "[!] bug - a date that does not match http/1.1"
- "rules was generated\ninvalid date: [%s] should be %zu characters"
- "long but is not\n", dateBuf, strlen(dateBuf));
- // restore the locale and timezone
- setlocale(LC_ALL, saved[0]);
- strcpy(tzname[0], saved[1]); setenv("TZ", tzname[0], 1); tzset();
- // store the header in a contiguous buffer
- snprintf(buf, 2048, fmt, dateBuf, docLen);
- #ifdef PRINT_HTTP_HEADER
- // send http response to stderr
- fprintf(stderr, buf);
- #endif
- // set output length
- *outLen = strlen(buf);
- return buf;
- }
- char *httpEcho(char *s, int len, int *limit) {
- int headerLen, prediction;
- char *p, *buf, *header, *out = "Hola! You sent: ";
- /* for http responses to fit inside of a fixed length buffer we may need
- * to limit "echo" responses because of overhead from the http header
- * contents and our own canned text, unfortunately we cannot easily and
- * precisely say what that limit is due to the http header having
- * a variable lenght header, (Content-Length)
- * Most HTTP servers limit this header to 8K, meaning that 1-4 decimal
- * digits can be used to represent lengths between 0 and 8000.
- *
- * predict the header length, then reduce len if needed to fit into
- * server.h FIM_BUFFER_LEN by multiplying each occurence of a printf format
- * substitution symbol by two, and subtracting the result from the length
- * of http-server.c response header format template length (TYPICAL_HEADER)
- * then add in the length of the date header and the number of digits
- * needed to represent the length of the message body subtract this total
- * from FIM_BUFFER_LEN -- this is just a prediction, after truncating length,
- * the number of digits needed to represent the new length could be fewer
- */
- prediction = (sizeof(TYPICAL_HEADER) - 1) - (2 * TYPICAL_HEADER_FORMAT_SUBSTITUTIONS);
- prediction += (RFC7231_DATE_LENGTH + intLen(len + strlen(out)));
- prediction = (FIM_BUFFER_LEN - prediction);
- // also remove the length required for canned text
- prediction -= strlen(out);
- // shorten the echoed part of the response when buffer limit would be reached
- if(prediction >= len); else {
- fprintf(stderr, "buffer can only fit %d of %d characters for the "
- "response to client\n", prediction, len);
- len = 0 < prediction ?prediction :0;
- }
- // get the response headers
- header = responseHeader(strlen(out) + len, &headerLen);
- // do not send too much data to the client
- if((0 < headerLen) && (300 > headerLen)); else {
- fprintf(stderr, "Why the weird amount of data?"
- "headerLen [%d]\n"
- "client data length [%d]\n"
- "my hola length [%zu]\n", headerLen, len, strlen(out));
- return out;
- }
- if(0) fprintf(stderr, "webpage length: head %d + server %zu + body %d = %zu\n",
- headerLen, strlen(out), len,
- strlen(out) + len + headerLen);
- // report the length of buffer for caller
- *limit = strlen(out) + len + headerLen;
- // generate a larger buffer
- buf = (char *) malloc(strlen(out) + len + headerLen);
- // make a copy of the pointer so we can copy data
- p = buf;
- // copy the header
- for(uint32_t i = headerLen; i--;) *p++ = *header++;
- // copy the canned out message
- for(uint32_t i = strlen(out); i--;) *p++ = *out++;
- // copy the client message
- for(uint32_t i = len; i--;) *p++ = *s++;
- return buf;
- }
|