int main (void) { int year, i; apr_time_t guess; apr_time_t offset = 0; /* apr_time_t offset = 0; */ /* apr_time_t offset = ((31 + 28) * 24 * 3600) - 1; */ apr_time_t secstodate, newsecs; char datestr[50]; for (year = 1970; year < 2038; ++year) { secstodate = year2secs[year - 1970] + offset; gm_timestr_822(datestr, secstodate); secstodate *= APR_USEC_PER_SEC; newsecs = apr_date_parse_http(datestr); if (secstodate == newsecs) printf("Yes %4d %19" APR_TIME_T_FMT " %s\n", year, secstodate, datestr); else if (newsecs == APR_DATE_BAD) printf("No %4d %19" APR_TIME_T_FMT " %19" APR_TIME_T_FMT " %s\n", year, secstodate, newsecs, datestr); else printf("No* %4d %19" APR_TIME_T_FMT " %19" APR_TIME_T_FMT " %s\n", year, secstodate, newsecs, datestr); } srand48(978245L); for (i = 0; i < 10000; ++i) { guess = (time_t)mrand48(); if (guess < 0) guess *= -1; secstodate = guess + offset; gm_timestr_822(datestr, secstodate); secstodate *= APR_USEC_PER_SEC; newsecs = apr_date_parse_http(datestr); if (secstodate == newsecs) printf("Yes %" APR_TIME_T_FMT " %s\n", secstodate, datestr); else if (newsecs == APR_DATE_BAD) printf("No %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " %s\n", secstodate, newsecs, datestr); else printf("No* %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " %s\n", secstodate, newsecs, datestr); } exit(0); }
static void fcgi_write_response(mapcache_context_fcgi *ctx, mapcache_http_response *response) { if(response->code != 200) { printf("Status: %ld %s\r\n",response->code, err_msg(response->code)); } if(response->headers && !apr_is_empty_table(response->headers)) { const apr_array_header_t *elts = apr_table_elts(response->headers); int i; for(i=0; i<elts->nelts; i++) { apr_table_entry_t entry = APR_ARRAY_IDX(elts,i,apr_table_entry_t); printf("%s: %s\r\n", entry.key, entry.val); } } if(response->mtime) { char *datestr; char *if_modified_since = getenv("HTTP_IF_MODIFIED_SINCE"); datestr = apr_palloc(ctx->ctx.pool, APR_RFC822_DATE_LEN); apr_rfc822_date(datestr, response->mtime); printf("Last-Modified: %s\r\n", datestr); if(if_modified_since) { apr_time_t ims_time; apr_int64_t ims,mtime; mtime = apr_time_sec(response->mtime); ims_time = apr_date_parse_http(if_modified_since); ims = apr_time_sec(ims_time); if(ims >= mtime) { printf("Status: 304 Not Modified\r\n"); /* * "The 304 response MUST NOT contain a message-body" * https://tools.ietf.org/html/rfc2616#section-10.3.5 */ printf("\r\n"); return; } } } if(response->data) { printf("Content-Length: %ld\r\n\r\n", response->data->size); fwrite((char*)response->data->buf, response->data->size,1,stdout); } }
static void accept_headers(cache_handle_t *h, request_rec *r) { apr_table_t *cookie_table; const char *v; v = apr_table_get(h->resp_hdrs, "Content-Type"); if (v) { ap_set_content_type(r, v); apr_table_unset(h->resp_hdrs, "Content-Type"); } /* If the cache gave us a Last-Modified header, we can't just * pass it on blindly because of restrictions on future values. */ v = apr_table_get(h->resp_hdrs, "Last-Modified"); if (v) { ap_update_mtime(r, apr_date_parse_http(v)); ap_set_last_modified(r); apr_table_unset(h->resp_hdrs, "Last-Modified"); } /* The HTTP specification says that it is legal to merge duplicate * headers into one. Some browsers that support Cookies don't like * merged headers and prefer that each Set-Cookie header is sent * separately. Lets humour those browsers by not merging. * Oh what a pain it is. */ cookie_table = apr_table_make(r->pool, 2); apr_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL); apr_table_do(set_cookie_doo_doo, cookie_table, h->resp_hdrs, "Set-Cookie", NULL); apr_table_unset(r->err_headers_out, "Set-Cookie"); apr_table_unset(h->resp_hdrs, "Set-Cookie"); apr_table_overlap(r->headers_out, h->resp_hdrs, APR_OVERLAP_TABLES_SET); apr_table_overlap(r->err_headers_out, h->resp_err_hdrs, APR_OVERLAP_TABLES_SET); if (!apr_is_empty_table(cookie_table)) { r->err_headers_out = apr_table_overlay(r->pool, r->err_headers_out, cookie_table); } }
/** * Take two sets of headers, sandwich them together, and apply the result to * r->headers_out. * * To complicate this, a header may be duplicated in either table. Should a * header exist in the top table, all matching headers will be removed from * the bottom table before the headers are combined. The Warning headers are * handled specially. Warnings are added rather than being replaced, while * in the case of revalidation 1xx Warnings are stripped. * * The Content-Type and Last-Modified headers are then re-parsed and inserted * into the request. */ void cache_accept_headers(cache_handle_t *h, request_rec *r, apr_table_t *top, apr_table_t *bottom, int revalidation) { const char *v; if (revalidation) { r->headers_out = apr_table_make(r->pool, 10); apr_table_do(filter_header_do, r->headers_out, bottom, NULL); } else if (r->headers_out != bottom) { r->headers_out = apr_table_copy(r->pool, bottom); } apr_table_do(remove_header_do, r->headers_out, top, NULL); apr_table_do(add_header_do, r->headers_out, top, NULL); v = apr_table_get(r->headers_out, "Content-Type"); if (v) { ap_set_content_type(r, v); /* * Also unset possible Content-Type headers in r->headers_out and * r->err_headers_out as they may be different to what we have received * from the cache. * Actually they are not needed as r->content_type set by * ap_set_content_type above will be used in the store_headers functions * of the storage providers as a fallback and the HTTP_HEADER filter * does overwrite the Content-Type header with r->content_type anyway. */ apr_table_unset(r->headers_out, "Content-Type"); apr_table_unset(r->err_headers_out, "Content-Type"); } /* If the cache gave us a Last-Modified header, we can't just * pass it on blindly because of restrictions on future values. */ v = apr_table_get(r->headers_out, "Last-Modified"); if (v) { ap_update_mtime(r, apr_date_parse_http(v)); ap_set_last_modified(r); } }
AP_DECLARE(int) ap_scan_script_header_err_core(request_rec *r, char *buffer, int (*getsfunc) (char *, int, void *), void *getsfunc_data) { char x[MAX_STRING_LEN]; char *w, *l; int p; int cgi_status = HTTP_UNSET; apr_table_t *merge; apr_table_t *cookie_table; if (buffer) { *buffer = '\0'; } w = buffer ? buffer : x; /* temporary place to hold headers to merge in later */ merge = apr_table_make(r->pool, 10); /* The HTTP specification says that it is legal to merge duplicate * headers into one. Some browsers that support Cookies don't like * merged headers and prefer that each Set-Cookie header is sent * separately. Lets humour those browsers by not merging. * Oh what a pain it is. */ cookie_table = apr_table_make(r->pool, 2); apr_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL); while (1) { int rv = (*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data); if (rv == 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "Premature end of script headers: %s", apr_filepath_name_get(r->filename)); return HTTP_INTERNAL_SERVER_ERROR; } else if (rv == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "Script timed out before returning headers: %s", apr_filepath_name_get(r->filename)); return HTTP_GATEWAY_TIME_OUT; } /* Delete terminal (CR?)LF */ p = strlen(w); /* Indeed, the host's '\n': '\012' for UNIX; '\015' for MacOS; '\025' for OS/390 -- whatever the script generates. */ if (p > 0 && w[p - 1] == '\n') { if (p > 1 && w[p - 2] == CR) { w[p - 2] = '\0'; } else { w[p - 1] = '\0'; } } /* * If we've finished reading the headers, check to make sure any * HTTP/1.1 conditions are met. If so, we're done; normal processing * will handle the script's output. If not, just return the error. * The appropriate thing to do would be to send the script process a * SIGPIPE to let it know we're ignoring it, close the channel to the * script process, and *then* return the failed-to-meet-condition * error. Otherwise we'd be waiting for the script to finish * blithering before telling the client the output was no good. * However, we don't have the information to do that, so we have to * leave it to an upper layer. */ if (w[0] == '\0') { int cond_status = OK; /* PR#38070: This fails because it gets confused when a * CGI Status header overrides ap_meets_conditions. * * We can fix that by dropping ap_meets_conditions when * Status has been set. Since this is the only place * cgi_status gets used, let's test it explicitly. * * The alternative would be to ignore CGI Status when * ap_meets_conditions returns anything interesting. * That would be safer wrt HTTP, but would break CGI. */ if ((cgi_status == HTTP_UNSET) && (r->method_number == M_GET)) { cond_status = ap_meets_conditions(r); } apr_table_overlap(r->err_headers_out, merge, APR_OVERLAP_TABLES_MERGE); if (!apr_is_empty_table(cookie_table)) { /* the cookies have already been copied to the cookie_table */ apr_table_unset(r->err_headers_out, "Set-Cookie"); r->err_headers_out = apr_table_overlay(r->pool, r->err_headers_out, cookie_table); } return cond_status; } /* if we see a bogus header don't ignore it. Shout and scream */ #if APR_CHARSET_EBCDIC /* Chances are that we received an ASCII header text instead of * the expected EBCDIC header lines. Try to auto-detect: */ if (!(l = strchr(w, ':'))) { int maybeASCII = 0, maybeEBCDIC = 0; unsigned char *cp, native; apr_size_t inbytes_left, outbytes_left; for (cp = w; *cp != '\0'; ++cp) { native = apr_xlate_conv_byte(ap_hdrs_from_ascii, *cp); if (apr_isprint(*cp) && !apr_isprint(native)) ++maybeEBCDIC; if (!apr_isprint(*cp) && apr_isprint(native)) ++maybeASCII; } if (maybeASCII > maybeEBCDIC) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "CGI Interface Error: Script headers apparently ASCII: (CGI = %s)", r->filename); inbytes_left = outbytes_left = cp - w; apr_xlate_conv_buffer(ap_hdrs_from_ascii, w, &inbytes_left, w, &outbytes_left); } } #endif /*APR_CHARSET_EBCDIC*/ if (!(l = strchr(w, ':'))) { char malformed[(sizeof MALFORMED_MESSAGE) + 1 + MALFORMED_HEADER_LENGTH_TO_SHOW]; strcpy(malformed, MALFORMED_MESSAGE); strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW); if (!buffer) { /* Soak up all the script output - may save an outright kill */ while ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data)) { continue; } } ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, "%s: %s", malformed, apr_filepath_name_get(r->filename)); return HTTP_INTERNAL_SERVER_ERROR; } *l++ = '\0'; while (*l && apr_isspace(*l)) { ++l; } if (!strcasecmp(w, "Content-type")) { char *tmp; /* Nuke trailing whitespace */ char *endp = l + strlen(l) - 1; while (endp > l && apr_isspace(*endp)) { *endp-- = '\0'; } tmp = apr_pstrdup(r->pool, l); ap_content_type_tolower(tmp); ap_set_content_type(r, tmp); } /* * If the script returned a specific status, that's what * we'll use - otherwise we assume 200 OK. */ else if (!strcasecmp(w, "Status")) { r->status = cgi_status = atoi(l); r->status_line = apr_pstrdup(r->pool, l); } else if (!strcasecmp(w, "Location")) { apr_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Content-Length")) { apr_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Content-Range")) { apr_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Transfer-Encoding")) { apr_table_set(r->headers_out, w, l); } /* * If the script gave us a Last-Modified header, we can't just * pass it on blindly because of restrictions on future values. */ else if (!strcasecmp(w, "Last-Modified")) { ap_update_mtime(r, apr_date_parse_http(l)); ap_set_last_modified(r); } else if (!strcasecmp(w, "Set-Cookie")) { apr_table_add(cookie_table, w, l); } else { apr_table_add(merge, w, l); } } return OK; }
static int lisp_handler (request_rec * r) { lisp_cfg_t * cfg = (ap_get_module_config ((r->per_dir_config), (&lisp_module))); int content_length = (-1); int keep_socket_p = 0; apr_socket_t * socket; const char * request_content_length = 0; cfg = local_lisp_cfg(cfg); if ((strcmp ((r->handler), "lisp-handler")) != 0) return (DECLINED); /* Open a connection to the Lisp process. */ ML_LOG_DEBUG (r, "open lisp connection"); CVT_ERROR ((open_lisp_socket (cfg)), "opening connection to Lisp"); (SERVER_SOCKET_SAFE_P (cfg)) = 0; socket = (SERVER_SOCKET (cfg)); /* Remove any timeout that might be left over from earlier. */ ML_LOG_DEBUG (r, "clear socket timeout"); CVT_ERROR ((apr_socket_timeout_set (socket, (-1))), "clearing read timeout"); /* Convert environment variables to headers and send them. */ ML_LOG_DEBUG (r, "write env-var headers"); ap_add_cgi_vars (r); ap_add_common_vars (r); if ((r->subprocess_env) != 0) CVT_ERROR ((copy_headers ((r->subprocess_env), map_env_var_to_lisp_header, socket)), "writing to Lisp"); /* Send this before client headers so ASSOC can be used to grab it without worrying about some joker sending a server-id header of his own. (Robert Macomber) */ ML_LOG_DEBUG (r, "write headers"); CVT_ERROR ((write_lisp_header (socket, "server-id", (cfg->server_id))), "writing to Lisp"); CVT_ERROR ((write_lisp_header (socket, "server-baseversion", AP_SERVER_BASEVERSION)), "writing to Lisp"); CVT_ERROR ((write_lisp_header (socket, "modlisp-version", VERSION_STRING)), "writing to Lisp"); CVT_ERROR ((write_lisp_header (socket, "modlisp-major-version", "2")), "writing to Lisp"); /* Send all the remaining headers. */ if ((r->headers_in) != 0) CVT_ERROR ((copy_headers ((r->headers_in), map_header_to_lisp_header, socket)), "writing to Lisp"); request_content_length = apr_table_get(r->headers_in, "Content-Length"); /* Send the end-of-headers marker. */ ML_LOG_DEBUG (r, "write end-of-headers"); CVT_ERROR ((write_lisp_line (socket, "end")), "writing to Lisp"); /* Send the request entity. */ RELAY_HTTP_ERROR (ap_setup_client_block (r, REQUEST_CHUNKED_DECHUNK)); if (ap_should_client_block (r)) { char buffer [4096]; ML_LOG_DEBUG (r, "write entity"); while (1) { long n_read = (ap_get_client_block (r, buffer, (sizeof (buffer)))); if (n_read < 0) { ML_LOG_PERROR (r, "error reading from client"); close_lisp_socket (cfg); return (HTTP_INTERNAL_SERVER_ERROR); } /* for chunked case, when nread == 0, we will write * a terminating 0.*/ { apr_status_t status = APR_SUCCESS; /* if there's no Content-Type header, the data must be chunked */ if (request_content_length == NULL) status = write_lisp_data_chunk (socket, buffer, n_read); else if (n_read != 0) status = write_lisp_data (socket, buffer, n_read); if (APR_SUCCESS != status) { while ((ap_get_client_block (r, buffer, sizeof(buffer))) > 0) ; ML_LOG_ERROR (status, r, "writing to Lisp"); close_lisp_socket (cfg); return (HTTP_INTERNAL_SERVER_ERROR); } } if( n_read == 0) break; } } /* Set up read timeout so we don't hang forever if Lisp is wedged. */ ML_LOG_DEBUG (r, "set socket timeout"); CVT_ERROR ((apr_socket_timeout_set (socket, READ_TIMEOUT)), "setting read timeout"); /* Read the headers and process them. */ ML_LOG_DEBUG (r, "read headers"); while (1) { char header_name [4096]; char header_value [MAX_STRING_LEN]; CVT_ERROR ((read_lisp_line (socket, header_name, (sizeof (header_name)))), "reading from Lisp"); if ((strcasecmp (header_name, "end")) == 0) break; CVT_ERROR ((read_lisp_line (socket, header_value, (sizeof (header_value)))), "reading from Lisp"); if ((strcasecmp (header_name, "content-type")) == 0) { char * tmp = (apr_pstrdup ((r->pool), header_value)); ap_content_type_tolower (tmp); (r->content_type) = tmp; } else if ((strcasecmp (header_name, "status")) == 0) { (r->status) = (atoi (header_value)); (r->status_line) = (apr_pstrdup ((r->pool), header_value)); } else if ((strcasecmp (header_name, "location")) == 0) apr_table_set ((r->headers_out), header_name, header_value); else if ((strcasecmp (header_name, "content-length")) == 0) { apr_table_set ((r->headers_out), header_name, header_value); content_length = (atoi (header_value)); } else if ((strcasecmp (header_name, "lisp-content-length")) == 0) { content_length = (atoi (header_value)); } else if ((strcasecmp (header_name, "last-modified")) == 0) { apr_time_t mtime = (apr_date_parse_http (header_value)); r->mtime = mtime; ap_set_last_modified (r); } else if ((strcasecmp (header_name, "keep-socket")) == 0) keep_socket_p = (atoi (header_value)); else if ((strcasecmp (header_name, "log-emerg")) == 0) ap_log_error (APLOG_MARK, APLOG_EMERG, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-alert")) == 0) ap_log_error (APLOG_MARK, APLOG_ALERT, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-crit")) == 0) ap_log_error (APLOG_MARK, APLOG_CRIT, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-error")) == 0) ap_log_error (APLOG_MARK, APLOG_ERR, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-warning")) == 0) ap_log_error (APLOG_MARK, APLOG_WARNING, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-notice")) == 0) ap_log_error (APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-info")) == 0) ap_log_error (APLOG_MARK, APLOG_INFO, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-debug")) == 0) ap_log_error (APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log")) == 0) ap_log_error (APLOG_MARK, APLOG_ERR, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "note")) == 0) { char * p = (strchr (header_value, ' ')); if (p != 0) { (*p++) = '\0'; apr_table_setn ((r->notes), (apr_pstrdup ((r->pool), header_value)), (apr_pstrdup ((r->pool), p))); } } else if ((strcasecmp (header_name, "set-cookie")) == 0) { apr_table_add ((r->headers_out), header_name, header_value); } else apr_table_set ((r->headers_out), header_name, header_value); } /* Copy the reply entity from Lisp to the client... */ // if (content_length > 0) { unsigned int n_read = 0; input_buffer_t * buffer; ML_LOG_DEBUG (r, "read entity"); CVT_ERROR ((get_input_buffer (socket, (&buffer))), "reading from Lisp"); while ((buffer->start) <= (buffer->end)) { apr_status_t fill_status; unsigned int n_bytes = ((buffer->end) - (buffer->start)); n_read += n_bytes; if ((content_length >= 0) && (n_read > content_length)) { n_bytes -= (n_read - content_length); n_read -= (n_read - content_length); } /* ...unless it's a HEAD request. */ if (!r->header_only && !write_client_data (r, (buffer->start), n_bytes)) { close_lisp_socket (cfg); return (HTTP_INTERNAL_SERVER_ERROR); } (buffer->start) += n_bytes; if (n_read == content_length) break; fill_status = fill_input_buffer (socket); if ((fill_status == APR_EOF) && (content_length < 0)) break; else CVT_ERROR (fill_status, "reading from Lisp"); } } if ((content_length < 0) || (!keep_socket_p)) CVT_ERROR ((close_lisp_socket (cfg)), "closing connection to Lisp"); else (SERVER_SOCKET_SAFE_P (cfg)) = 1; ML_LOG_DEBUG (r, "request finished"); return (OK); }
apr_status_t jxr_process_response_headers(request_rec *r, char *buf) { apr_status_t rv = APR_SUCCESS; apr_size_t pos; apr_size_t len; char type; int nHeaders; int i; char name[MAX_STRING_LEN]; char value[MAX_STRING_LEN]; apr_size_t nlen, vlen; table *merge; table *cookie_table; char *w, *l; type = jxr_msg_get_type(buf); len = jxr_msg_get_length(buf, &pos); if (type != BLOCKTYPE_HTTP_HEADER) { // Invalid data compat_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, "mod_jaxer: invalid data type (%c) received, while expecting a header (%d)", type, BLOCKTYPE_HTTP_HEADER); return HTTP_INTERNAL_SERVER_ERROR; } /* temporary place to hold headers to merge in later */ merge = ap_make_table(r->pool, 10); cookie_table = ap_make_table(r->pool, 2); ap_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL); nHeaders = jxr_msg_get_int16(buf, &pos); for (i=0; i<nHeaders; i++) { // Process one header -- name -- val nlen = jxr_msg_get_string(buf, &pos, name); vlen = jxr_msg_get_string(buf, &pos, value); w = name; l = value; if (!strcasecmp(w, "Content-type")) { char *tmp; /* Nuke trailing whitespace */ char *endp = l + strlen(l) - 1; while (endp > l && apr_isspace(*endp)) { *endp-- = '\0'; } tmp = ap_pstrdup(r->pool, l); ap_content_type_tolower(tmp); ap_set_content_type(r, tmp); } else if (!strcasecmp(w, "Status")) { /* * If the server returned a specific status, that's what * we'll use - otherwise we assume 200 OK. */ r->status = atoi(l); r->status_line = ap_pstrdup(r->pool, l); } else if (!strcasecmp(w, "Location")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Content-Length")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Content-Range")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Transfer-Encoding")) { ap_table_set(r->headers_out, w, l); } else if (!strcasecmp(w, "Last-Modified")) { /* * If the script gave us a Last-Modified header, we can't just * pass it on blindly because of restrictions on future values. */ ap_update_mtime(r, apr_date_parse_http(l)); ap_set_last_modified(r); } else if (!strcasecmp(w, "Set-Cookie")) { ap_table_add(cookie_table, w, l); } else { ap_table_add(merge, w, l); } } // now merge stuff ap_overlap_tables(r->err_headers_out, merge, AP_OVERLAP_TABLES_MERGE); if (!ap_is_empty_table(cookie_table)) { /* the cookies have already been copied to the cookie_table */ ap_table_unset(r->err_headers_out, "Set-Cookie"); r->err_headers_out = ap_overlay_tables(r->pool, r->err_headers_out, cookie_table); } return rv; }