Sun, 15 May 2022 08:56:00 +0200
make sure the http stream is finished if headers are sent
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * * THE BSD LICENSE * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // code from open webserver // safs/cgi.cpp #include "cgiutils.h" #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include "../util/util.h" #include "../util/pblock.h" #include "../daemon/protocol.h" //----------------------------------------------------------------------------- // Macros //----------------------------------------------------------------------------- #define CGI_VERSION "CGI/1.1" // CGI env sizing #define MAX_CGI_COMMON_VARS 23 #define MAX_CGI_SPECIFIC_VARS 10 #define MAX_CGI_CLIENT_AUTH_VARS 64 //----------------------------------------------------------------------------- // cgi_parse_query //----------------------------------------------------------------------------- int cgi_parse_query(char **argv, int n, char *q) { int i = 0; for (;;) { // Parse an arg from the query string char *arg = q; while (*q != ' ' && *q != '\0') q++; // Caller must ensure argv[] is appropriately sized WS_ASSERT(i < n); if (i >= n) return -1; // Escape any shell characters (does a MALLOC on our behalf) char c = *q; *q = '\0'; argv[i] = util_sh_escape(arg); *q = c; // Unescape this arg, bailing on error if (!argv[i] || !util_uri_unescape_strict(argv[i])) return -1; // We successfully parsed another arg i++; // We're done when we hit the end of the query string if (*q == '\0') break; q++; } return i; } //----------------------------------------------------------------------------- // cgi_create_argv //----------------------------------------------------------------------------- char **cgi_create_argv(const char *program, const char *script, const char *query) { int nargs = 1; // The script name, if any, will be argv[1] if (script) nargs++; // Turn '+' into ' ' in query string, counting the number of arg as we go char *qargs = NULL; if (query && !strchr(query, '=')) { qargs = STRDUP(query); if (!qargs) return NULL; nargs++; for (char *t = qargs; *t; t++) { if (*t == '+') *t = ' '; if (*t == ' ') nargs++; } } // Allocate the argv[] array, leaving room for the trailing NULL char **argv = (char **) MALLOC((nargs + 1) * sizeof(char *)); if (!argv) return NULL; int i = 0; // Set argv[0] to the program name argv[i] = STRDUP(program); i++; // Set argv[1] to the script name if (script) { argv[i] = STRDUP(script); i++; } // Parse the query string into argv[] if (qargs) { int n = cgi_parse_query(&argv[i], nargs - i, qargs); if (n > 0) i += n; } // Mark end of argv[] argv[i] = NULL; return argv; } void cgi_free_argv(char **args) { int i = 0; while(args[i] != NULL) { free(args[i]); i++; } free(args); } //---------------------------------------------------------------------------- // cgi_get_request_uri //---------------------------------------------------------------------------- char* cgi_get_request_uri(Request *req) { // Extract the encoded URI from the request line if possible char *clf_request = pblock_findkeyval(pb_key_clf_request, req->reqpb); if (clf_request) { // Find the beginning of the method char *method = clf_request; while (*method && isspace(*method)) method++; // Skip over the method char *uri = method; while (*uri && !isspace(*uri)) uri++; // Find the beginning of the URI while (*uri && isspace(*uri)) uri++; // Find the end of the URI char *end = uri; while (*end && !isspace(*end)) end++; // Make a copy of the uri int len = end - uri; char* request_uri = (char*) MALLOC(len+1); memcpy(request_uri, uri, len); request_uri[len] = '\0'; return request_uri; } // No request line. return NULL; } //----------------------------------------------------------------------------- // cgi_specific_vars //----------------------------------------------------------------------------- char** cgi_specific_vars(Session *sn, Request *rq, const char *args, char** env, int scriptVars) { int y; register pblock *pb; char c, *t, *u; pb = rq->reqpb; int x; env = util_env_create(env, MAX_CGI_SPECIFIC_VARS, &x); env[x++] = util_env_str("GATEWAY_INTERFACE", CGI_VERSION); // Added error check for missing request information. t = pblock_findval("protocol", pb); if (t == NULL) { log_ereport(LOG_FAILURE, "cgi_specific_vars", "missing \"protocol\" in rq->reqpb"); return NULL; } env[x++] = util_env_str("SERVER_PROTOCOL", t); t = pblock_findval("method", pb); if (t == NULL) { log_ereport(LOG_FAILURE, "cgi_specific_vars", "missing \"request method\" in rq->reqpb"); return NULL; } env[x++] = util_env_str("REQUEST_METHOD", t); if (args) env[x++] = util_env_str("QUERY_STRING", args); // set REQUEST_URI if (rq->orig_rq) { t = cgi_get_request_uri(rq->orig_rq); } else { t = cgi_get_request_uri(rq); } if (t) { env[x++] = util_env_str("REQUEST_URI", t); FREE(t); } if (scriptVars) { t = pblock_findval("uri", pb); /* Simulate CGI URIs by truncating path info */ if ((u = pblock_findval("path-info", rq->vars))) { y = strlen(t) - strlen(u); if (y >= 0) { c = t[y]; t[y] = '\0'; } env[x++] = util_env_str("SCRIPT_NAME", t); if (y >= 0) { t[y] = c; } env[x++] = util_env_str("PATH_INFO", u); // TODO /* if((t = INTservact_translate_uri2(u, sn, rq))) { env[x++] = util_env_str("PATH_TRANSLATED", t); // keep path-translated in rq->vars since we may need it // during fastcgi processing pblock_nvinsert("path-translated", t, rq->vars); FREE(t); } */ } else { env[x++] = util_env_str("SCRIPT_NAME", t); } if ((t = pblock_findval("path", rq->vars))) env[x++] = util_env_str("SCRIPT_FILENAME", t); } env[x] = NULL; return env; } //----------------------------------------------------------------------------- // cgi_common_vars //----------------------------------------------------------------------------- char** cgi_common_vars(Session *sn, Request *rq, char **env) { char *t; int x; env = util_env_create(env, MAX_CGI_COMMON_VARS, &x); /* if (!_env_initialized) cgi_env_init(); if (_env_path) env[x++] = util_env_str("PATH", _env_path); if (_env_tz) env[x++] = util_env_str("TZ", _env_tz); if (_env_lang) env[x++] = util_env_str("LANG", _env_lang); if (_env_ldpath) env[x++] = util_env_str(LIBRARY_PATH, _env_ldpath); env[x++] = util_env_str("SERVER_SOFTWARE", PRODUCT_HEADER_ID"/"PRODUCT_VERSION_ID); */ // TODO: enable //NSString srvName, portStr; //char buf1[256], buf2[64]; //srvName.useStatic(buf1, sizeof(buf1), 0); //portStr.useStatic(buf2, sizeof(buf2), 0); //GetServerHostnameAndPort(*rq, *sn, srvName, portStr); char *scheme; char *host; uint16_t port; http_get_scheme_host_port(sn, rq, &scheme, &host, &port); char portstr[8]; snprintf(portstr, 8, "%" PRIu16, (int)port); env[x++] = util_env_str("SERVER_PORT", portstr); env[x++] = util_env_str("SERVER_NAME", host); //t = http_uri2url_dynamic("","",sn,rq); //env[x++] = util_env_str("SERVER_URL", t); //FREE(t); char *ip; ip = pblock_findval("ip", sn->client); t = session_dns(sn); env[x++] = util_env_str("REMOTE_HOST", (t ? t : ip)); env[x++] = util_env_str("REMOTE_ADDR", ip); if((t = pblock_findval("auth-user", rq->vars))) { env[x++] = util_env_str("REMOTE_USER", t); if((t = pblock_findval("auth-type", rq->vars))) { env[x++] = util_env_str("AUTH_TYPE", t); } if((t = pblock_findval("auth-userdn", rq->vars))) { env[x++] = util_env_str("REMOTE_USERDN", t); } } if((t = pblock_findval("password-policy", rq->vars))) { /* chrisk made up this variable name */ env[x++] = util_env_str("PASSWORD_POLICY", t); } // Handle Apache ErrorDocument-style variables from the send-error SAF if (rq->orig_rq != rq) { if ((t = pblock_findval("uri", rq->orig_rq->reqpb))) { env[x++] = util_env_str("REDIRECT_URL", t); } if ((t = pblock_findval("status", rq->orig_rq->srvhdrs))) { env[x++] = util_env_str("REDIRECT_STATUS", t); } } if(sn->ssl) { env[x++] = util_env_str("HTTPS", "ON"); } #if 0 if (GetSecurity(sn)) { env[x++] = util_env_str("HTTPS", "ON"); if (t = pblock_findval("keysize", sn->client)) env[x++] = util_env_str("HTTPS_KEYSIZE", t); if (t = pblock_findval("secret-keysize", sn->client)) env[x++] = util_env_str("HTTPS_SECRETKEYSIZE", t); t = pblock_findval("ssl-id", sn->client); env[x++] = util_env_str("HTTPS_SESSIONID", t ? t : (char *)""); unsigned char random_bytes[NUM_RANDOM_BYTES + 2]; char random_string[NUM_RANDOM_BYTES*2 + 2]; PK11_GenerateRandom(random_bytes, NUM_RANDOM_BYTES); int i; for(i = 0; i < NUM_RANDOM_BYTES; i++) { sprintf(&random_string[i*2], "%02x", (unsigned int)(random_bytes[i] & 0xff)); } random_string[NUM_RANDOM_BYTES*2] = '\0'; env[x++] = util_env_str("HTTPS_RANDOM", random_string); } else { env[x++] = util_env_str("HTTPS", "OFF"); } #endif env[x] = NULL; //env = cgi_client_auth_vars(sn, rq, env); // TODO: enable return env; }