void test_date_functions() { char buf[50]; time_t time; assert(current_http_date(buf, 50) == 0); info("Current time in HTTP format: %s", buf); assert(parse_http_date(buf, &time) == 0); info("Current time in seconds: %ld", time); time += 81; format_http_date(&time, buf, 50); info("Current time in HTTP format(add 81 secs): %s", buf); }
static int handle_cache(request_t *req, response_t *resp, const struct stat *st, const mod_static_conf_t *conf) { const char *if_mod_since, *if_none_match; char *etag; time_t mtime, req_mtime; int not_modified = 0; char *buf; char *cache_control; mtime = st->st_mtime; if_mod_since = request_get_header(req, "if-modified-since"); if (if_mod_since != NULL && parse_http_date(if_mod_since, &req_mtime) == 0 && req_mtime == mtime) { debug("Resource not modified"); not_modified = 1; } buf = response_alloc(resp, 32); format_http_date(&mtime, buf, 32); response_set_header(resp, "Last-Modified", buf); if (conf->enable_etag) { etag = generate_etag(st); if (not_modified) { if_none_match = request_get_header(req, "if-none-match"); if (if_none_match == NULL || strcmp(etag, if_none_match) != 0) { not_modified = 0; } } response_set_header(resp, "ETag", etag); } if (conf->expire_hours >= 0) { buf = response_alloc(resp, 32); mtime += conf->expire_hours * 3600; format_http_date(&mtime, buf, 32); response_set_header(resp, "Expires", buf); cache_control = response_alloc(resp, 20); snprintf(cache_control, 20, "max-age=%d", conf->expire_hours * 3600); } else { cache_control = "no-cache"; } response_set_header(resp, "Cache-Control", cache_control); return not_modified; }
/* sezere 1 cookie z retezce str, na zacatku nesmi byt zadne whitechars * na konci muze byt strednik nebo 0 * cookie musi byt ve tvaru nazev=hodnota, kolem rovnase nesmi byt zadne mezery * (respektive mezery se budou pocitat do nazvu a do hodnoty) */ int set_cookie(struct terminal *term, unsigned char *url, unsigned char *str) { int noval = 0; struct cookie *cookie; struct c_server *cs; unsigned char *p, *q, *s, *server, *date; d_opt = &dd_opt; int accept_cookies = dds.allow_cookies; if (accept_cookies == ACCEPT_NONE) { return 0; } for (p = str; *p != ';' && *p; p++) { /*if (WHITECHAR(*p)) return 0;*/ } for (q = str; *q != '='; q++) if (!*q || q >= p) { noval = 1; break; } if (str == q || q + 1 == p) return 0; cookie = mem_alloc(sizeof(struct cookie)); server = get_host_name(url); cookie->name = memacpy(str, q - str); cookie->value = !noval ? memacpy(q + 1, p - q - 1) : NULL; cookie->server = stracpy(server); date = parse_header_param(str, cast_uchar "expires", 0); if (date) { cookie->expires = parse_http_date(date); /* kdo tohle napsal a proc ?? */ /*if (! cookie->expires) cookie->expires++;*/ /* no harm and we can use zero then */ mem_free(date); } else cookie->expires = 0; if (!(cookie->path = parse_header_param(str, cast_uchar "path", 0))) { /*unsigned char *w;*/ cookie->path = stracpy(cast_uchar "/"); /* add_to_strn(&cookie->path, document); for (w = cookie->path; *w; w++) if (end_of_dir(cookie->path, *w)) { *w = 0; break; } for (w = cookie->path + strlen(cast_const_char cookie->path) - 1; w >= cookie->path; w--) if (*w == '/') { w[1] = 0; break; } */ } else { if (cookie->path[0] != '/') { add_to_strn(&cookie->path, cast_uchar "x"); memmove(cookie->path + 1, cookie->path, strlen(cast_const_char cookie->path) - 1); cookie->path[0] = '/'; } } if (!(cookie->domain = parse_header_param(str, cast_uchar "domain", 0))) cookie->domain = stracpy(server); if (cookie->domain[0] == '.') memmove(cookie->domain, cookie->domain + 1, strlen(cast_const_char cookie->domain)); if ((s = parse_header_param(str, cast_uchar "secure", 0))) { cookie->secure = 1; mem_free(s); } else cookie->secure = 0; if (check_domain_security(server, cookie->domain)) { mem_free(cookie->domain); cookie->domain = stracpy(server); } foreach (cs, c_servers) if (!strcasecmp(cast_const_char cs->server, cast_const_char server)) { if (cs->accpt) goto ok; else { free_cookie(cookie); mem_free(cookie); mem_free(server); return 0; } } if (accept_cookies != ACCEPT_ALL) { free_cookie(cookie); mem_free(cookie); mem_free(server); return 1; } ok: accept_cookie(cookie); mem_free(server); return 0; }
void http_got_header(struct connection *c, struct read_buffer *rb) { int cf; int state = c->state != S_PROC ? S_GETH : S_PROC; unsigned char *head; unsigned char *cookie, *ch; int a, h, version; unsigned char *d; struct cache_entry *e; struct http_connection_info *info; unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url); set_timeout(c); info = c->info; if (rb->close == 2) { unsigned char *h; if (!c->tries && (h = get_host_name(host))) { if (info->bl_flags & BL_NO_CHARSET) { del_blacklist_entry(h, BL_NO_CHARSET); } else { add_blacklist_entry(h, BL_NO_CHARSET); c->tries = -1; } mem_free(h); } setcstate(c, S_CANT_READ); retry_connection(c); return; } rb->close = 0; again: if ((a = get_header(rb)) == -1) { setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (!a) { read_from_socket(c, c->sock1, rb, http_got_header); setcstate(c, state); return; } if (a != -2) { head = mem_alloc(a + 1); memcpy(head, rb->data, a); head[a] = 0; kill_buffer_data(rb, a); } else { head = stracpy("HTTP/0.9 200 OK\r\nContent-Type: text/html\r\n\r\n"); } if (get_http_code(head, &h, &version) || h == 101) { mem_free(head); setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (check_http_server_bugs(host, c->info, head) && is_connection_restartable(c)) { mem_free(head); setcstate(c, S_RESTART); retry_connection(c); return; } ch = head; while ((cookie = parse_http_header(ch, "Set-Cookie", &ch))) { unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url); set_cookie(NULL, host, cookie); mem_free(cookie); } if (h == 100) { mem_free(head); state = S_PROC; goto again; } if (h < 200) { mem_free(head); setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (h == 204) { mem_free(head); setcstate(c, S_HTTP_204); http_end_request(c, 0); return; } if (h == 304) { mem_free(head); setcstate(c, S_OK); http_end_request(c, 1); return; } if ((h == 500 || h == 502 || h == 503 || h == 504) && http_bugs.retry_internal_errors && is_connection_restartable(c)) { /* !!! FIXME: wait some time ... */ mem_free(head); setcstate(c, S_RESTART); retry_connection(c); return; } if (!c->cache && get_cache_entry(c->url, &c->cache)) { mem_free(head); setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } e = c->cache; e->http_code = h; if (e->head) mem_free(e->head); e->head = head; if ((d = parse_http_header(head, "Expires", NULL))) { time_t t = parse_http_date(d); if (t && e->expire_time != 1) e->expire_time = t; mem_free(d); } if ((d = parse_http_header(head, "Pragma", NULL))) { if (!casecmp(d, "no-cache", 8)) e->expire_time = 1; mem_free(d); } if ((d = parse_http_header(head, "Cache-Control", NULL))) { char *f = d; while (1) { while (*f && (*f == ' ' || *f == ',')) f++; if (!*f) break; if (!casecmp(f, "no-cache", 8) || !casecmp(f, "must-revalidate", 15)) { e->expire_time = 1; } if (!casecmp(f, "max-age=", 8)) { if (e->expire_time != 1) e->expire_time = time(NULL) + atoi(f + 8); } while (*f && *f != ',') f++; } mem_free(d); } #ifdef HAVE_SSL if (c->ssl) { int l = 0; if (e->ssl_info) mem_free(e->ssl_info); e->ssl_info = init_str(); add_num_to_str(&e->ssl_info, &l, SSL_get_cipher_bits(c->ssl, NULL)); add_to_str(&e->ssl_info, &l, "-bit "); add_to_str(&e->ssl_info, &l, SSL_get_cipher_version(c->ssl)); add_to_str(&e->ssl_info, &l, " "); add_to_str(&e->ssl_info, &l, (unsigned char *)SSL_get_cipher_name(c->ssl)); } #endif if (e->redirect) mem_free(e->redirect), e->redirect = NULL; if (h == 301 || h == 302 || h == 303 || h == 307) { if ((h == 302 || h == 307) && !e->expire_time) e->expire_time = 1; if ((d = parse_http_header(e->head, "Location", NULL))) { unsigned char *user, *ins; unsigned char *newuser, *newpassword; if (!parse_url(d, NULL, &user, NULL, NULL, NULL, &ins, NULL, NULL, NULL, NULL, NULL, NULL) && !user && ins && (newuser = get_user_name(host))) { if (*newuser) { int ins_off = ins - d; newpassword = get_pass(host); if (!newpassword) newpassword = stracpy(""); add_to_strn(&newuser, ":"); add_to_strn(&newuser, newpassword); add_to_strn(&newuser, "@"); extend_str(&d, strlen(newuser)); ins = d + ins_off; memmove(ins + strlen(newuser), ins, strlen(ins) + 1); memcpy(ins, newuser, strlen(newuser)); mem_free(newpassword); } mem_free(newuser); } if (e->redirect) mem_free(e->redirect); e->redirect = d; e->redirect_get = h == 303; } } if (!e->expire_time && strchr(c->url, POST_CHAR)) e->expire_time = 1; info->close = 0; info->length = -1; info->version = version; if ((d = parse_http_header(e->head, "Connection", NULL)) || (d = parse_http_header(e->head, "Proxy-Connection", NULL))) { if (!strcasecmp(d, "close")) info->close = 1; mem_free(d); } else if (version < 11) info->close = 1; cf = c->from; c->from = 0; if ((d = parse_http_header(e->head, "Content-Range", NULL))) { if (strlen(d) > 6) { d[5] = 0; if (!(strcasecmp(d, "bytes")) && d[6] >= '0' && d[6] <= '9') { #if defined(HAVE_STRTOLL) long long f = strtoll(d + 6, NULL, 10); #elif defined(HAVE_STRTOQ) longlong f = strtoq(d + 6, NULL, 10); #else long f = strtol(d + 6, NULL, 10); if (f == MAXLONG) f = -1; #endif if (f >= 0 && (off_t)f >= 0 && (off_t)f == f) c->from = f; } } mem_free(d); } if (cf && !c->from && !c->unrestartable) c->unrestartable = 1; if (c->from > cf || c->from < 0) { setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if ((d = parse_http_header(e->head, "Content-Length", NULL))) { unsigned char *ep; #if defined(HAVE_STRTOLL) long long l = strtoll(d, (char **)(void *)&ep, 10); #elif defined(HAVE_STRTOQ) longlong l = strtoq(d, (char **)(void *)&ep, 10); #else long l = strtol(d, (char **)(void *)&ep, 10); if (l == MAXLONG) l = -1; #endif if (!*ep && l >= 0 && (off_t)l >= 0 && (off_t)l == l) { if (!info->close || version >= 11) info->length = l; if (c->from + l >= 0) c->est_length = c->from + l; } mem_free(d); } if ((d = parse_http_header(e->head, "Accept-Ranges", NULL))) { if (!strcasecmp(d, "none") && !c->unrestartable) c->unrestartable = 1; mem_free(d); } else { if (!c->unrestartable && !c->from) c->unrestartable = 1; } if (info->bl_flags & BL_NO_RANGE && !c->unrestartable) c->unrestartable = 1; if ((d = parse_http_header(e->head, "Transfer-Encoding", NULL))) { if (!strcasecmp(d, "chunked")) { info->length = -2; info->chunk_remaining = -1; } mem_free(d); } if (!info->close && info->length == -1) info->close = 1; if ((d = parse_http_header(e->head, "Last-Modified", NULL))) { if (e->last_modified && strcasecmp(e->last_modified, d)) { delete_entry_content(e); if (c->from) { c->from = 0; mem_free(d); setcstate(c, S_MODIFIED); retry_connection(c); return; } } if (!e->last_modified) e->last_modified = d; else mem_free(d); } if (!e->last_modified && (d = parse_http_header(e->head, "Date", NULL))) e->last_modified = d; if (info->length == -1 || (version < 11 && info->close)) rb->close = 1; read_http_data(c, rb); }
static Cookie *parse_cookie(Octstr *cookiestr) { char *v = NULL; char *p = NULL; int delta = 0; Cookie *c = NULL; Octstr **f = NULL; if (cookiestr == NULL) { error(0, "parse_cookie: NULL argument"); return NULL; } v = gw_strdup(octstr_get_cstr (cookiestr)); p = strtok(v, ";"); c = cookie_create(); /* Never returns NULL */ while (p != NULL) { while (isspace((int)*p)) p++; /* Skip leading whitespace */ if (strncasecmp("version", p, 7) == 0) f = &c -> version; else if (strncasecmp("path", p, 4) == 0) f = &c -> path; else if (strncasecmp("domain", p, 6) == 0) f = &c -> domain; /* XXX DAVI: Shouldn't we check if domain is similar * to real domain, and to set domain to * real domain if not set by header ??? */ else if (strncasecmp("max-age", p, 7) == 0) { c -> max_age = atol(strrchr (p, '=') + 1); p = strtok(NULL, ";"); continue; } else if (strncasecmp("expires", p, 7) == 0) { delta = parse_http_date(p); if (delta != -1) c->max_age = delta; p = strtok(NULL, ";"); continue; } else if (strncasecmp("comment", p, 7) == 0 ) { /* Ignore comments */ p = strtok(NULL, ";"); continue; } else if (strncasecmp("secure", p, 6) == 0 ) { /* XXX DAVI: this should processed */ p = strtok(NULL, ";"); continue; } else { /* Name value pair - this should be first */ char *equals = NULL; if ((equals = strchr(p, '=')) != NULL) { *equals = '\0'; c->name = octstr_create(p); c->value = octstr_create(equals + 1); } else { error(0, "parse_cookie: Bad name=value cookie component (%s)", p); cookie_destroy(c); return NULL; } p = strtok(NULL, ";"); continue; } if (*f != NULL) { /* Undefined behaviour - 4.2.2 */ error(0, "parse_cookie: Duplicate cookie field (%s), discarding", p); p = strtok(NULL, ";"); continue; } *f = octstr_create("$"); octstr_append_cstr(*f, p); p = strtok(NULL, ";"); } /* Process version - 4.3.4 * XXX DAVI: Altough it seems to be "MUST" in RFC, no one sends a Version * tag when it's value is "0" if (c->version == NULL) { c->version = octstr_create(""); octstr_append_cstr(c->version, "$Version=\"0\";"); } */ gw_free (v); return c; }
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) { size_t mime_type_size = 0; char http_last_modified[49]; if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static); char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size); if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static); if (wsgi_req->if_modified_since_len) { time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len); if (st->st_mtime <= ims) { uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16); return uwsgi_response_write_headers_do(wsgi_req); } } #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename); #endif size_t fsize = st->st_size; if (wsgi_req->range_to) { fsize = wsgi_req->range_to - wsgi_req->range_from; if (fsize > (size_t)st->st_size) { fsize = st->st_size; } } else { // reset in case of inconsistent size if (wsgi_req->range_from > fsize) { wsgi_req->range_from = 0; fsize = 0 ; } else { fsize -= wsgi_req->range_from; } } // HTTP status if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) { if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1; } else { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1; } #ifdef UWSGI_PCRE uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st); uwsgi_add_expires_path_info(wsgi_req, st); uwsgi_add_expires_uri(wsgi_req, st); #endif // Content-Type (if available) if (mime_type_size > 0 && mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1; // check for content-type related headers uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st); } // increase static requests counter uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++; // nginx if (uwsgi.file_serve_mode == 1) { if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1; // this is the final header (\r\n added) int size = set_http_date(st->st_mtime, http_last_modified); if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1; } // apache else if (uwsgi.file_serve_mode == 2) { if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1; // this is the final header (\r\n added) int size = set_http_date(st->st_mtime, http_last_modified); if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1; } // raw else { // here we need to choose if we want the gzip variant; if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) { if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1; } // set Content-Length (to fsize NOT st->st_size) if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1; if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) { // here use teh original size !!! if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1; } int size = set_http_date(st->st_mtime, http_last_modified); if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1; // if it is a HEAD request just skip transfer if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { wsgi_req->status = 200; return 0; } // Ok, the file must be transferred from uWSGI // offloading will be automatically managed int fd = open(real_filename, O_RDONLY); if (fd < 0) return -1; // fd will be closed in the following function uwsgi_response_sendfile_do(wsgi_req, fd, wsgi_req->range_from, fsize); } wsgi_req->status = 200; return 0; }