const char * generate_websocket_resp(const char * req, size_t reqlen, char * dest, size_t destlen) { /* char origin[256]; */ /* char protocol[256]; */ /* char key1[256]; */ /* char key2[256]; */ char key[256]; char upgrade[64]; /* get_header_value(req, reqlen, "Origin", origin, sizeof(origin)); */ /* get_header_value(req, reqlen, "Sec-WebSocket-Protocol", protocol, sizeof(protocol)); */ get_header_value(req, reqlen, "Upgrade", upgrade, sizeof(upgrade)); /* get_header_value(req, reqlen, "Sec-WebSocket-Key1", key1, sizeof(key1)); */ /* get_header_value(req, reqlen, "Sec-WebSocket-Key2", key2, sizeof(key2)); */ get_header_value(req, reqlen, "Sec-WebSocket-Key", key, sizeof(key)); if (key[0] != '\0') { char key_sha1[128]; char key_base64[128]; SHA1Context sha; strcat(key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); SHA1Reset(&sha); SHA1Input(&sha, ( const unsigned char * )key, strlen(key)); SHA1Result(&sha); memset(key_sha1, 0, sizeof(key_sha1)); memset(key_base64, 0, sizeof(key_base64)); int i, j; for (i = 0; i < 5; i++) { for (j = 0; j < 4; j++) { key_sha1[i*4+j] = sha.Message_Digest[i] << (8*j) >> 24; } } base64_encode(key_sha1, strlen(key_sha1), key_base64, sizeof(key_base64)); snprintf(dest, destlen, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: %s\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n\r\n", upgrade, key_base64); return dest; }
/********************************************************************* * * Function : is_imageurl * * Description : Given a URL, decide whether it is an image or not, * using either the info from a previous +image action * or, #ifdef FEATURE_IMAGE_DETECT_MSIE, and the browser * is MSIE and not on a Mac, tell from the browser's accept * header. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : True (nonzero) if URL is an image, false (0) * otherwise * *********************************************************************/ int is_imageurl(struct client_state *csp) { #ifdef FEATURE_IMAGE_DETECT_MSIE char *tmp; tmp = get_header_value(csp->headers, "User-Agent:"); if (tmp && strstr(tmp, "MSIE") && !strstr(tmp, "Mac_")) { tmp = get_header_value(csp->headers, "Accept:"); if (tmp && strstr(tmp, "image/gif")) { /* Client will accept HTML. If this seems counterintuitive, * blame Microsoft. */ return(0); } else { return(1); } } #endif /* def FEATURE_IMAGE_DETECT_MSIE */ return ((csp->action->flags & ACTION_IMAGE) != 0); }
cloud_blob_properties blob_response_parsers::parse_blob_properties(const web::http::http_response& response) { cloud_blob_properties properties; properties.m_etag = parse_etag(response); properties.m_last_modified = parse_last_modified(response); properties.m_lease_status = parse_lease_status(response); properties.m_lease_state = parse_lease_state(response); properties.m_lease_duration = parse_lease_duration(response); properties.m_size = parse_blob_size(response); auto& headers = response.headers(); properties.m_page_blob_sequence_number = utility::conversions::scan_string<int64_t>(get_header_value(headers, ms_header_blob_sequence_number)); properties.m_append_blob_committed_block_count = utility::conversions::scan_string<int>(get_header_value(headers, ms_header_blob_committed_block_count)); properties.m_cache_control = get_header_value(headers, web::http::header_names::cache_control); properties.m_content_disposition = get_header_value(headers, header_content_disposition); properties.m_content_encoding = get_header_value(headers, web::http::header_names::content_encoding); properties.m_content_language = get_header_value(headers, web::http::header_names::content_language); properties.m_content_type = get_header_value(headers, web::http::header_names::content_type); properties.m_type = parse_blob_type(get_header_value(headers, ms_header_blob_type)); properties.m_content_md5 = get_header_value(headers, ms_header_blob_content_md5); if (properties.m_content_md5.empty()) { properties.m_content_md5 = get_header_value(headers, web::http::header_names::content_md5); } properties.m_server_encrypted = response_parsers::parse_boolean(get_header_value(headers, ms_header_server_encrypted)); properties.m_is_incremental_copy = response_parsers::parse_boolean(get_header_value(headers, ms_header_incremental_copy)); return properties; }
/* * Sets into the saved_request the designated filename, according to configured base * directory and request data (URI, headers, etc). Also creates the base directory if it * doesn't exist */ static int set_filename(tee_saved_request *sr) { apr_time_exp_t t; apr_time_exp_gmt(&t, sr->time_enqueued); // Obtaining directory name const char *dir; dir = apr_psprintf(sr->pool, "%s/%04d%02d%02d/%02d", sr->base_dir, 1900 + t.tm_year, t.tm_mon + 1, t.tm_mday, t.tm_hour); // Creating directory if needed apr_status_t rc = apr_dir_make_recursive(dir, APR_FPROT_OS_DEFAULT, sr->pool); if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, sr->server, "tee: Cannot create directory %s: %s", dir, tee_get_error_string(rc, sr->pool)); return 1; } // Setting file name unsigned long file_id = ((unsigned long) t.tm_min * 60 + t.tm_sec) * 1000000 + t.tm_usec; // usec in hour char b[MAX_FILENAME_LEN]; // Filename is cut in case the URI is too long const char *rec_id = get_header_value(sr, sr->id_header, ""); const char *host = get_header_value(sr, "Host", ""); apr_snprintf(b, MAX_FILENAME_LEN, "%010lu_%s_%s_%s%s", file_id, rec_id, sr->method, host, sr->uri); tee_replace(b, "/", '_'); // Replace the slash (invalid character in file names) sr->filename = apr_psprintf(sr->pool, "%s/%s_%d", dir, b, sr->status); return 0; }
static void set_distiller_type_generic(DistillerBuffer *mime_headers, const char *url, const char *user, C_DistillerType *dtype) { char *mimetype; int mimetype_len; char disttype[MAX_ARG_STRING + MAX_MIMETYPE + 1]; /* * Here if no X-Route header: use MIME type and/or username. */ mimetype = (char *)get_header_value(mime_headers, "content-type", &mimetype_len, NULL, NULL); if (mimetype == NULL) { if (user == NULL || *user == '\0') sprintf(disttype, "text/html"); else sprintf(disttype, "%s/text/html", user); } else { if (user && *user) sprintf(disttype, "%s/", user); else disttype[0] = '\0'; strncat(disttype, mimetype, mimetype_len); } SET_DISTILLER_TYPE(*dtype, disttype); }
int is_websocket_header(const char * data, size_t datalen) { char value[512]; if (get_header_value(data, datalen, "Connection", value, sizeof(value)) == 0) { if (strstr(value, "Upgrade")) { if (get_header_value(data, datalen, "Upgrade", value, 512) == 0) { // version 13 is 'websocket' if (strcasestr(value, "WebSocket")) { return 1; } else { printf("Can not found websocket in %s\n", value); } } } } return 0; }
static void set_distiller_type(DistillerBuffer *mime_headers, const char *url, const char *user, C_DistillerType *dtype) { const char *route = NULL; int route_len; char *disttype; if ((route = get_header_value(mime_headers, "x-route",&route_len,NULL,NULL)) == NULL) { /* Aggregator? */ if (strncasecmp(url, fe_agg_string, strlen(fe_agg_string)) == 0) { /* distiller "type" is everything up to but not incl next slash */ char disttype_tmp[256]; int i,j; for (i=0, j=strlen(fe_agg_string); i < strlen(url) && url[j] != '/'; i++,j++) ; strncpy(disttype_tmp, url+strlen(fe_agg_string), i); disttype_tmp[i] = '\0'; SET_DISTILLER_TYPE(*dtype, disttype_tmp); } else { /* generic transformation */ set_distiller_type_generic(mime_headers, url, user, dtype); } } else { /* pop off next element, up to a semicolon */ char *header_value = (char *)ALLOCA(route_len+1); char *semicolon; strncpy(header_value, route, route_len); header_value[route_len] = '\0'; if ((semicolon = strchr(header_value, ';')) != NULL) { int i; for (i=0; i<route_len && route[i] != ';'; i++) ; disttype = (char*)ALLOCA(i+2); strncpy(disttype, route, i); disttype[i] = '\0'; insert_header(mime_headers, "x-route", semicolon+1, 0); } else { /* no semicolon, this is the last guy in the list */ disttype = (char *)ALLOCA(route_len+2); strncpy(disttype, route, route_len); disttype[route_len] = '\0'; } delete_header(mime_headers, "x-route"); SET_DISTILLER_TYPE(*dtype, disttype); } }
int get_cookies(List *headers, const WSPMachine *sm) { Octstr *header = NULL; Octstr *value = NULL; Cookie *cookie = NULL; long pos = 0; /* * This can happen if the user aborts while the HTTP request is pending from the server. * In that case, the session machine is destroyed and is not available to this function * for cookie caching. */ if (sm == NULL) { info (0, "No session machine for cookie retrieval"); return 0; } for (pos = 0; pos < gwlist_len(headers); pos++) { header = gwlist_get(headers, pos); /* debug ("wap.wsp.http", 0, "get_cookies: Examining header (%s)", octstr_get_cstr (header)); */ if (strncasecmp ("set-cookie", octstr_get_cstr (header),10) == 0) { debug ("wap.wsp.http", 0, "Caching cookie (%s)", octstr_get_cstr (header)); if ((value = get_header_value (header)) == NULL) { error (0, "get_cookies: No value in (%s)", octstr_get_cstr(header)); continue; } /* Parse the received cookie */ if ((cookie = parse_cookie(value)) != NULL) { /* Check to see if this cookie is already present */ if (have_cookie(sm->cookies, cookie) == 1) { debug("wap.wsp.http", 0, "parse_cookie: Cookie present"); cookie_destroy(cookie); continue; } else { add_cookie_to_cache(sm, cookie); debug("wap.wsp.http", 0, "get_cookies: Added (%s)", octstr_get_cstr(cookie -> name)); } } } } debug("wap.wsp.http", 0, "get_cookies: End"); return 0; }
/* * HTTP headers looked OK, and we were able to determine what type of * distiller was needed, so go ahead and do the distillation, returning * the results to the client. If distillation fails, return the * original content and headers to the client. * * ARGS: * i: URL (BUG::shouldn't be needed - it's currently used to * determine distiller type for "aggregator" virtual-site URLs ) * i: input to distiller (from previous "pipestage" or from server) * o: output from distiller * o: distiller type descriptor * i: argument list for distiller * * RETURNS: Distiller status for the distillation * REENTRANT: yes * SIDE EFFECTS: * If distillation succeeds, fills in new headers (for return to client) * in DistillerOutput structure * ASSUMTPIONS: * None */ static DistillerStatus do_distillation(const char *url, DistillerInput *dinp, DistillerOutput *doutp, C_DistillerType *dtype, ArgumentList *al) { DistillerStatus result = distFatalError; Argument *arg; const char *whichuser = "******"; const char *mime; int mime_len; /* * HTTP headers look OK. Extract the MIME type, figure out what * distiller to use, and dispatch to it. */ if ((arg = getArgumentFromIdInList(al, FRONT_USERID))) { whichuser = ARG_STRING(*arg); } /* * If this is the set-prefs page, be sure the user's args get munged into it * REMOVED by fox since it interferes with the "mini-httpd" worker (miniserver.pl): * this routing is now enforced by X-Route instead */ if (0 && strcasecmp(url, fe_set_prefs_url) == 0) { SET_DISTILLER_TYPE(*dtype, "transend/text/html"); } else { set_distiller_type(&dinp->metadata, (const char *)url, whichuser, dtype); } if ((mime = get_header_value(&dinp->metadata, "content-type", &mime_len, NULL, NULL)) != NULL) { strncpy(dinp->mimeType, mime, MIN(mime_len,MAX_MIMETYPE-1)); dinp->mimeType[MIN(mime_len,MAX_MIMETYPE-1)] = '\0'; } else { strcpy(dinp->mimeType, "text/html"); } result = Distill(dtype, al->arg, al->nargs, dinp, doutp); return result; }
int get_header_double(PyObject* header, const char* keyword, double* val, double def, HeaderGetFlags flags) { /* nonnegative isn't currently used for doubles/floats. But if needed one could simply remove the assert again and implement the negative check. */ assert(!(flags & HDR_FAIL_VAL_NEGATIVE)); PyObject* keyval = get_header_value(header, keyword, flags); if (keyval == NULL) { *val = def; return PyErr_Occurred() ? GET_HEADER_FAILED : GET_HEADER_DEFAULT_USED; } double tmp = PyFloat_AsDouble(keyval); Py_DECREF(keyval); if (PyErr_Occurred()) { return GET_HEADER_FAILED; } *val = tmp; return GET_HEADER_SUCCESS; }
int get_header_longlong(PyObject* header, const char* keyword, long long* val, long long def, HeaderGetFlags flags) { PyObject* keyval = get_header_value(header, keyword, flags); if (keyval == NULL) { *val = def; return PyErr_Occurred() ? GET_HEADER_FAILED : GET_HEADER_DEFAULT_USED; } long long tmp = PyLong_AsLongLong(keyval); Py_DECREF(keyval); if (PyErr_Occurred()) { return GET_HEADER_FAILED; } if ((flags & HDR_FAIL_VAL_NEGATIVE) && (tmp < 0)) { PyErr_Format(PyExc_ValueError, "%s should not be negative.", keyword); return GET_HEADER_FAILED; } *val = tmp; return GET_HEADER_SUCCESS; }
int get_header_string(PyObject* header, const char* keyword, char* val, const char* def, HeaderGetFlags flags) { /* nonnegative doesn't make sense for strings*/ assert(!(flags & HDR_FAIL_VAL_NEGATIVE)); PyObject* keyval = get_header_value(header, keyword, flags); if (keyval == NULL) { strncpy(val, def, 72); return PyErr_Occurred() ? GET_HEADER_FAILED : GET_HEADER_DEFAULT_USED; } PyObject* tmp = PyUnicode_AsLatin1String(keyval); // FITS header values should always be ASCII, but Latin1 is on the // safe side Py_DECREF(keyval); if (tmp == NULL) { /* could always fail to allocate the memory or such like. */ return GET_HEADER_FAILED; } strncpy(val, PyBytes_AsString(tmp), 72); Py_DECREF(tmp); return GET_HEADER_SUCCESS; }
/********************************************************************* * * Function : trust_url FIXME: I should be called distrust_url * * Description : Calls is_untrusted_url to determine if the URL is trusted * and if not, returns a HTTP 304 response with a reject message. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : NULL => trusted, else http_response. * *********************************************************************/ struct http_response *trust_url(struct client_state *csp) { struct http_response *rsp; struct map * exports; char buf[BUFFER_SIZE]; char *p; struct url_spec **tl; struct url_spec *t; jb_err err; /* * Don't bother to work on trusted URLs */ if (!is_untrusted_url(csp)) { return NULL; } /* * Else, prepare a response: */ if (NULL == (rsp = alloc_http_response())) { return cgi_error_memory(); } exports = default_exports(csp, NULL); if (exports == NULL) { free_http_response(rsp); return cgi_error_memory(); } /* * Export the protocol, host, port, and referrer information */ err = map(exports, "hostport", 1, csp->http->hostport, 1); if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1); if (!err) err = map(exports, "path", 1, csp->http->path, 1); if (NULL != (p = get_header_value(csp->headers, "Referer:"))) { if (!err) err = map(exports, "referrer", 1, html_encode(p), 0); } else { if (!err) err = map(exports, "referrer", 1, "unknown", 1); } if (err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } /* * Export the trust list */ p = strdup(""); for (tl = csp->config->trust_list; (t = *tl) != NULL ; tl++) { sprintf(buf, "<li>%s</li>\n", t->spec); string_append(&p, buf); } err = map(exports, "trusted-referrers", 1, p, 0); if (err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } /* * Export the trust info, if available */ if (csp->config->trust_info->first) { struct list_entry *l; p = strdup(""); for (l = csp->config->trust_info->first; l ; l = l->next) { sprintf(buf, "<li> <a href=\"%s\">%s</a><br>\n",l->str, l->str); string_append(&p, buf); } err = map(exports, "trust-info", 1, p, 0); } else { err = map_block_killer(exports, "have-trust-info"); } if (err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } /* * Export the force prefix or the force conditional block killer */ #ifdef FEATURE_FORCE_LOAD err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1); #else /* ifndef FEATURE_FORCE_LOAD */ err = map_block_killer(exports, "force-support"); #endif /* ndef FEATURE_FORCE_LOAD */ if (err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } /* * Build the response */ err = template_fill_for_cgi(csp, "untrusted", exports, rsp); if (err) { free_http_response(rsp); return cgi_error_memory(); } return finish_http_response(rsp); }
HTTP_Status server_dispatch(ArgumentList *al, task_t *tsk) { int thrindex = TASK_THRINDEX(tsk); int agg = 0; int nfound; HTTP_Status retcode = HTTP_NO_ERR; Request *hp = (Request *)TASK_DATA(tsk); #ifdef LOGGING struct loginfo *lo = hp->lo; #endif INST_set_thread_state(thrindex, THR_CACHE); /* * If we got here, we know the request is either GET or POST, * or this is a URL in the frontend's namespace */ tsk->task_age = 0; /* no pipe stages done yet */ /*if (*hp->url == '/' || strncasecmp(hp->url, fe_agg_string, strlen(fe_agg_string)) == 0) {*/ if (is_server_url(hp->url)==gm_True) { /* this is a URL in the frontend's namespace, or an aggregator URL */ const char *workerName, *val; int val_len, len, to_copy, already_read; char *orig_hdrs, *eoh, *new_hdrs, *body; extern Options runtime_options; orig_hdrs = DistillerBufferData(&hp->cli_hdrs); eoh = strstr(orig_hdrs, "\r\n\r\n"); if (eoh==NULL) { retcode = HTTP_ERR_MALFORMED_REQUEST; goto DISPATCH_RETURN; } eoh += 4; /* clone the headers */ DistillerBufferAlloc(&hp->svr_hdrs, eoh-orig_hdrs+1); new_hdrs = DistillerBufferData(&hp->svr_hdrs); memcpy(new_hdrs, orig_hdrs, eoh-orig_hdrs); *(new_hdrs+(eoh-orig_hdrs)) = '\0'; DistillerBufferSetLength(&hp->svr_hdrs, eoh - orig_hdrs); DistillerBufferFreeMe(&hp->svr_hdrs, gm_True); /* * look for the content-length field; * if found, read the rest of the data and create svr_data */ if ((val = get_header_value(&hp->cli_hdrs, "content-length", &val_len, NULL, NULL)) != NULL) { len = strtoul(val, NULL, 0); if (len < 0) { retcode = HTTP_ERR_MALFORMED_REQUEST; goto DISPATCH_RETURN; } already_read = DistillerBufferLength(&hp->cli_hdrs) - (eoh - orig_hdrs); if (len <= already_read) { to_copy = len; } else { to_copy = already_read; } DistillerBufferAlloc(&hp->svr_data, len+1); body = DistillerBufferData(&hp->svr_data); memcpy(body, eoh, to_copy); /* get the rest of the data from the socket */ if (to_copy < len) { if (readline_or_timeout(hp, len - to_copy, body+to_copy) != (len-to_copy)) { retcode = HTTP_ERR_MALFORMED_REQUEST; goto DISPATCH_RETURN; } } /* add a trailing '\0' */ *(body+len) = '\0'; DistillerBufferSetLength(&hp->svr_data, len); } workerName = Options_Find(runtime_options, "frontend.myurl.dispatch"); if (workerName==NULL) workerName = "myurl/dispatch"; insert_header(&hp->svr_hdrs, "X-Route", workerName, 1); hp->svr_http_status = 200; /* everything's ok with this HTTP request */ } else { INST_timestamp(thrindex, m_cachestart); if (hp->method[0] == 'g' || hp->method[0] == 'G') { /* handle GET */ #ifdef OLD /* * HACK HACK HACK - this should be replaced with the real interface that * does a regexp match on URL to determine if any aggregator should get * dibs before the original content is fetched. * * Any references in this function to variable 'agg' represent a place * where the hack was spliced in. */ if (strncasecmp(hp->url, fe_agg_string, strlen(fe_agg_string)) != 0) { /* not an aggregator call */ #endif agg = 0; retcode = do_get(hp, al); if (retcode != HTTP_NO_ERR) { goto DISPATCH_RETURN; } #ifdef OLD } else { /* aggregator call */ abort(); agg = 1; /* don't clone the client headers - just point to them. */ DistillerBufferSetStatic(&hp->svr_hdrs, DistillerBufferData(&hp->cli_hdrs), DistillerBufferLength(&hp->cli_hdrs)); /* since we're pointing to a copy, don't try to free */ DistillerBufferFreeMe(&hp->svr_hdrs, gm_False); } #endif } else { /* handle POST */ retcode = do_post(hp, al); if (retcode != HTTP_NO_ERR) { /* post failed! report error to client */ goto DISPATCH_RETURN; } } INST_timestamp(thrindex, m_cachedone); /* * if there was an HTTP-level error (response code not "200"), bypass * the remainder straight to client. */ nfound = sscanf(DistillerBufferData(&hp->svr_hdrs), "%*s %lu", &hp->svr_http_status); if (nfound < 1) { /* no status found */ retcode = HTTP_ERR_GET_FAILED; hp->svr_http_status = 0; } else { retcode = HTTP_NO_ERR; } } #ifdef LOGGING lo->http_response = hp->svr_http_status;; /* log HTTP server response */ #endif /* LOGGING */ /* * Note that HTTP_NO_ERR means "transaction to server succeeded" (ie * at the transport level). it does NOT necessarily mean that the * HTTP *operation* (eg GET) succeeded -- the HTTP status code tells that. */ DISPATCH_RETURN: return retcode; }
utility::string_t parse_lease_id(const web::http::http_response& response) { return get_header_value(response, ms_header_lease_id); }
lease_status parse_lease_status(const web::http::http_response& response) { return parse_lease_status(get_header_value(response, ms_header_lease_status)); }
utility::string_t get_header_value(const web::http::http_response& response, const utility::string_t& header) { return get_header_value(response.headers(), header); }
utility::string_t parse_etag(const web::http::http_response& response) { return get_header_value(response, web::http::header_names::etag); }
int proxyServerLoadRequest(ProxyServer *p, const char *uniqueId, RequestRecord *rec) { reset_request_record(rec); char file_name[512]; struct stat stat_buf; snprintf(file_name, sizeof(file_name), "%s/%s.req", stringAsCString(p->persistenceFolder), uniqueId); rec->fd = open(file_name, O_RDONLY); DIE(p, rec->fd, "Failed to open request file."); int status = fstat(rec->fd, &stat_buf); DIE(p, status, "Failed to get request file size."); rec->map.length = stat_buf.st_size; //Save the size //If file size is 0 then just return if (rec->map.length == 0) { return 0; } rec->map.buffer = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_SHARED, rec->fd, 0); if (rec->map.buffer == MAP_FAILED) { DIE(p, -1, "Failed to map request file."); } //We are good to go. Start parsing. String *str = newString(); int state = PARSE_METHOD; for (size_t i = 0; i < rec->map.length; ++i) { char ch = rec->map.buffer[i]; //printf("[%c %d]", ch, state); if (ch == '\r') { continue; //Ignored } if (state == PARSE_METHOD) { if (ch == ' ') { if (strcmp("CONNECT", stringAsCString(rec->method)) == 0) { state = PARSE_CONNECT_ADDRESS; } else { state = PARSE_PATH; } continue; } stringAppendChar(rec->method, ch); continue; } if (state == PARSE_PATH) { if (ch == '?') { state = PARSE_QUERY_STRING; continue; } if (ch == ' ') { state = PARSE_PROTOCOL_VERSION; continue; } stringAppendChar(rec->path, ch); continue; } if (state == PARSE_QUERY_STRING) { if (ch == ' ') { state = PARSE_PROTOCOL_VERSION; continue; } stringAppendChar(rec->queryString, ch); continue; } if (state == PARSE_PROTOCOL_VERSION) { if (ch == '\n') { state = PARSE_HEADER_NAME; continue; } //Don't store version continue; } if (state == PARSE_CONNECT_ADDRESS) { if (ch == ' ') { state = PARSE_PROTOCOL_VERSION; continue; } //Don't store address continue; } if (state == PARSE_HEADER_NAME) { if (ch == ':') { arrayAdd(rec->headerNames, newStringWithString(str)); str->length = 0; state = PARSE_HEADER_VALUE; continue; } if (ch == '\n') { //End of request headers rec->headerBuffer.buffer = rec->map.buffer; rec->headerBuffer.length = i + 1; rec->bodyBuffer.buffer = rec->map.buffer + i + 1; rec->bodyBuffer.length = rec->map.length - rec->headerBuffer.length; //End parsing for now break; } stringAppendChar(str, ch); continue; } if (state == PARSE_HEADER_VALUE) { if (ch == '\n') { arrayAdd(rec->headerValues, newStringWithString(str)); str->length = 0; state = PARSE_HEADER_NAME; continue; } if ((str->length == 0) && ch == ' ') { //Skip leading space. continue; } stringAppendChar(str, ch); continue; } } deleteString(str); //Parse URL parameters parse_url_params(rec->queryString->buffer, rec->queryString->length, rec->parameterNames, rec->parameterValues); //If form post then parse request body for parameters String *contentType = get_header_value(CONTENT_TYPE, rec); if (contentType != NULL && stringEqualsCString(contentType, FORM_ENC) && rec->bodyBuffer.length > 0) { parse_url_params(rec->bodyBuffer.buffer, rec->bodyBuffer.length, rec->parameterNames, rec->parameterValues); } //It is safe to close the file now. It will //closed anyway by reset method. close(rec->fd); rec->fd = -1; return 0; }
lease_duration parse_lease_duration(const web::http::http_response& response) { return parse_lease_duration(get_header_value(response, ms_header_lease_duration)); }
DistillerStatus proxy_dispatch(ArgumentList *al, task_t *t) { DistillerStatus status; /* result of this pipe stage distillation */ DistillerInput din; DistillerOutput dout; Request *hp = (Request *)TASK_DATA(t); C_DistillerType dtype; int thrindex = TASK_THRINDEX(t); DistillerStatus retcode; int redispatch = 0; char *static_route = NULL; int static_route_initialized = 0; #ifdef LOGGING struct loginfo *lo = hp->lo; #endif /* * Initialize for *first* pipe stage. */ DistillerBufferClone(&din.data, &hp->svr_data); DistillerBufferFreeMe(&din.data, gm_True); /* * Make a **copy** of the server headers, because they may get * overwritten when preparing headers to send to a distiller. */ DistillerBufferClone(&din.metadata, &hp->svr_hdrs); DistillerBufferFreeMe(&din.metadata, gm_True); do { const char *char_tmp; char content_type[MIME_TYPE_MAX+1]; int content_type_len; Argument *arg; int num_tries_left; /* * Initialize for next pipe stage. */ status = distFatalError; #ifdef LOGGING /* * Log original content-length */ char_tmp = get_header_value(&din.metadata, "content-length", &content_type_len, NULL, NULL); if (char_tmp != NULL) lo->size_before = strtoul(char_tmp, NULL, 0); else lo->size_before = -1; #endif /* LOGGING */ char_tmp = get_header_value(&din.metadata, "content-type", &content_type_len, NULL, NULL); if (char_tmp != NULL) { strncpy(content_type, char_tmp, MIN(content_type_len+1, MIME_TYPE_MAX)); content_type[MIN(content_type_len,MIME_TYPE_MAX)] = '\0'; } else { content_type[0] = '\0'; } /* if there are attributes after the content-type, remove them. */ if ((char_tmp = strchr((const char *)content_type, ';')) != NULL) *(char *)char_tmp = '\0'; /* chop any trailing spaces. */ if ((char_tmp = strchr((const char *)content_type, ' ')) != NULL) *(char *)char_tmp = '\0'; /* * Distillation is definitely needed, so go do it. In case of * distConnectionBroken error, (re)try at most N * times, where N is the value of the FRONT_RETRY_DISTILL argument, * or PERF_HTTP_RETRY_DISTILL by default. In case of any other * error, or if all retries fail, bypass the original content. In * case of distOk (success), return the distilled content. */ arg = getArgumentFromIdInList(al, FRONT_RETRY_DISTILL); num_tries_left = (arg ? ARG_INT(*arg) : PERF_HTTP_RETRY_DISTILL); INST_timestamp(thrindex, m_distillstart); /* * Add a "Location:" header so distillers have a way to get the URL of * this document, if they want. */ if (get_header_value(&din.metadata, "location", NULL, NULL, NULL) == NULL) { insert_header(&din.metadata, "Location", hp->url, 0); } do { INST_set_thread_state(thrindex, THR_DISTILLER); status = do_distillation(hp->url, &din, &dout, &dtype, al); } while (status == distConnectionBroken && num_tries_left-- > 0); #ifdef LOGGING lo->size_after = -status; /* pessimistically assume failure for log */ #endif /* LOGGING */ switch(status) { case distOk: case distRedispatch: /* * The rules for redispatch are as follows. * - If the response headers contain a nonempty X-Static-Route header, it * is the final authority. X-Static-Route is only saved the * first time it's seen. * - Otherwise, if the response code is distRedispatch, use the * default rules to figure out who to go to next. * - Otherwise, the response is distOk --> just finish. */ if (! static_route_initialized && DistillerBufferLength(&dout.metadata) > 0) { /* look for X-Static-Route */ int tmp_len; const char *static_route_hdr = get_header_value(&dout.metadata, "x-static-route", &tmp_len, NULL, NULL); if (static_route_hdr != NULL && tmp_len > 0) { static_route = ALLOCA(tmp_len+1); strncpy(static_route, static_route_hdr, tmp_len); static_route[tmp_len] = '\0'; static_route_initialized = 1; delete_header(&dout.metadata, "x-static-route"); } } if (static_route || (status == distRedispatch && !static_route_initialized)) { /* * this is a redispatch. * The redispatch strategy is as follows. Since the * DistillerInput pointer starts out being a *clone* of the * server headers and data, it's always safe to free it. THen move the * DistillerOutput pointer (result of previous pipestage) to the * DistillerInput pointer of this pipestage. */ DistillerBufferFree(&din.metadata); DistillerBufferFree(&din.data); DistillerBufferClone(&din.metadata, &dout.metadata); DistillerBufferClone(&din.data, &dout.data); DistillerBufferFree(&dout.metadata); DistillerBufferFree(&dout.data); /* * Fix the content-length and content-type, if nec. */ if (get_header_value(&din.metadata, "content-type",NULL,NULL,NULL) == NULL) insert_header(&din.metadata, "Content-type", din.mimeType, 1); if (get_header_value(&din.metadata, "content-length", NULL,NULL,NULL) == NULL) { char __tmp[12]; snprintf(__tmp, 11, "%lu", DistillerBufferLength(&din.data)); insert_header(&din.metadata, "Content-length", __tmp, 1); } if (static_route) { status = distRedispatch; /* add the X-Route header to this request */ insert_header(&din.metadata, "X-Route", static_route, 1); /* scan forward to the next component of the path */ while (*static_route && (*static_route != ';')) { static_route++; } if (*static_route == '\0') { static_route = NULL; } else { /* skip semicolon and any spaces */ while (*static_route && ((*static_route == ';') || (*static_route == ' '))) { static_route++; } if (*static_route == '\0') static_route = NULL; } } redispatch++; t->task_age++; /* "time to live" of this request */ retcode = distRedispatch; } else { /* * Here if any of the following were true: * - status was distOk and no static route header overrides this * - status was distRedispatch, but an existing static route header * indicates that we should override and finish with */ #ifdef LOGGING lo->size_after = DistillerBufferLength(&dout.data); #endif /* LOGGING */ status = retcode = distOk; } break; default: /* some other distiller/ptm error */ /* * BUG::we shouldn't make this visible to the user unless the * "guru" argument is set */ snprintf(hp->errmsg, HTTP_ERRMSG_MAX, (char *)FE_getDistillerStatusString(status)); /* retcode = HTTP_ERR_DISTILLER; XXX - XXX - XXX - */ retcode = status; break; } /* switch(status) */ /* Note that the data size is set last. So if the data size is not zero, it's a reasonable indication that this is a compelte set of valid measurements. (should really have a separate valid bit) */ INST_set_size(thrindex, DistillerBufferLength(&dout.data)); } while ((status == distRedispatch) && t->task_age <= PERF_REQUEST_TTL); /* do */ /* * "Copy" final output buffer to hp->pxy_hdrs/hp->pxy_data. (Really * we just copy the pointers, since the pxy_hdrs/pxy_data buffers * will be freed by the caller.) * * First generate headers to return to client. If last-stage * distiller returned * some headers, use them; otherwise, replace the "content-length" * and "content-type" fields of the ORIGINAL server headers with * new values deduced from the distiller data. */ if (status == distOk) { if (DistillerBufferLength(&(dout.metadata)) > 0) { DistillerBufferClone(&hp->pxy_hdrs, &dout.metadata); } else { /* * If the server headers begin with an HTTP/x.x response code, they are * headers from an origin server; OK to clone them and just replace the * content-type and content-length. Otherwise, they are probably * the result of a server-mode dispatch worker, which means they * actually look like request headers (not response headers), so delete them. */ if (DistillerBufferLength(&hp->svr_hdrs) > 0 && strncasecmp(DistillerBufferData(&hp->svr_hdrs), "HTTP/", 5) == 0) { DistillerBufferClone(&hp->pxy_hdrs, &hp->svr_hdrs); delete_header(&hp->pxy_hdrs, "content-type"); delete_header(&hp->pxy_hdrs, "content-length"); } else { char *s = "HTTP/1.0 200 OK\r\n\r\n"; int l = strlen(s); DistillerBufferAlloc(&hp->pxy_hdrs, 1+l); strcpy((char *)(hp->pxy_hdrs.data), s); DistillerBufferSetLength(&hp->pxy_hdrs,l); } } /* * Replace the "Content-length" and "Content-type" * headers with the correct info. Leave other headers * alone. */ if (get_header_value(&hp->pxy_hdrs, "content-type", NULL,NULL,NULL) == NULL) { insert_header(&hp->pxy_hdrs, "Content-type", dout.mimeType, 1); } if (get_header_value(&hp->pxy_hdrs,"content-length",NULL,NULL,NULL) == NULL) { char __tmp[12]; snprintf(__tmp, 11, "%lu", DistillerBufferLength(&dout.data)); insert_header(&hp->pxy_hdrs, "Content-length", __tmp, 1); } DistillerBufferClone(&hp->pxy_data, &dout.data); } if ((status == distOk) || (status == distRedispatch)) { DistillerBufferFree(&dout.data); DistillerBufferFree(&dout.metadata); } /* Always free this */ DistillerBufferFree(&din.data); DistillerBufferFree(&din.metadata); /* BUG::must do Clib_Put here??? */ return (retcode); }
void compose_request_buffer(http_request* request) { char *buffer = calloc(1, REQUEST_BUFFER_SIZE * sizeof(char)); ASSERT_ALLOCATE(buffer); size_t offset = 0; /* Start line */ int bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "%s ", get_method_name(request->method)); offset += bytes; /* Path, querystring, fragment */ if (strlen(request->path) > 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "%s", request->path); offset += bytes; } if (strlen(request->querystring) > 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "?%s", request->querystring); offset += bytes; } if (strlen(request->fragment) > 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "#%s ", request->fragment); offset += bytes; } bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, " %s\r\n", HTTP_1_1); offset += bytes; /* Start line ends here */ bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Accept: */*\r\n"); offset += bytes; /* Host */ if (is_match_pattern(request->host, REGEX_IPV4) != 0 && strcasecmp(request->host, "localhost") != 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Host: %s\r\n", request->host); offset += bytes; } else { char host[256] = {'\0'}; get_header_value("Host", request->additional_header, host); if (strlen(host) == 0) { if (request->port == PORT_HTTP) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Host: %s\r\n", request->host); offset += bytes; } else { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Host: %s:%d\r\n", request->host, request->port); offset += bytes; } } } if (request->http_keep_alive == HTTP_KEEP_ALIVE) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Connection: keep-alive\r\n"); offset += bytes; } if (strlen(request->bodydata) != 0 && request->file_upload != NULL) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Content-Type: multipart/form-data; boundary=%s\r\n", boundary); offset += bytes; } else if (strlen(request->content_type) > 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Content-Type: %s\r\n", request->content_type); offset += bytes; } if (request->additional_header != NULL) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "%s\r\n", request->additional_header); offset += bytes; } if (!(strlen(request->bodydata) != 0 && request->file_upload != NULL)) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Content-Length: %d\r\n", request->content_length); offset += bytes; /* Header ends here */ bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "\r\n"); offset += bytes; SCREEN(SCREEN_BLUE, stdout, "Http request header:\n"); SCREEN(SCREEN_GREEN, stdout, "%s", buffer); if (request->file_upload != NULL) { int fd = open(request->file_upload, O_RDONLY); if (fd < 0) { perror("open(2)"); exit(EXIT_FAILURE); } bytes = read(fd, buffer + offset, request->content_length); if (bytes != request->content_length) { SCREEN(SCREEN_RED, stderr, "Cannot read your input file: %s.\n", request->file_upload); exit(EXIT_FAILURE); } offset += bytes; } else if (strlen(request->bodydata) != 0) { bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "%s", request->bodydata); offset += bytes; } } else { /* Two multi-part */ /* We need to caculate Content-Length again */ char *extrabuffer = (char *) calloc(1, (REQUEST_BUFFER_SIZE) * sizeof(char)); ASSERT_ALLOCATE(extrabuffer); int bodyoffset = 0; bytes = snprintf(extrabuffer + bodyoffset, REQUEST_BUFFER_SIZE - bodyoffset, "%s\r\nContent-Disposition: form-data; name=\"img\", filename=\"%s\"\r\nContent-Type: image/jpeg\r\n\r\n", boundary, basename(request->file_upload)); bodyoffset += bytes; int fd = open(request->file_upload, O_RDONLY); if (fd < 0) { perror("open(2)"); exit(EXIT_FAILURE); } bytes = read(fd, extrabuffer + bodyoffset, request->file_size); if (bytes != request->file_size) { SCREEN(SCREEN_RED, stderr, "Cannot read your input file: %s.\n", request->file_upload); exit(EXIT_FAILURE); } bodyoffset += request->file_size; bytes = snprintf(extrabuffer + bodyoffset, REQUEST_BUFFER_SIZE - bodyoffset, "\r\n%s\r\nContent-Disposition: form-data; name=\"json\"\r\n\r\n%s\r\n%s\r\n", boundary, request->bodydata, boundary); bodyoffset += bytes; bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "Content-Length: %d\r\n", bodyoffset); offset += bytes; /* Header ends here */ bytes = snprintf(buffer + offset, REQUEST_BUFFER_SIZE - offset, "\r\n"); offset += bytes; SCREEN(SCREEN_BLUE, stdout, "Http request header:\n"); SCREEN(SCREEN_GREEN, stdout, "%s", buffer); memmove(buffer + offset, extrabuffer, bodyoffset); offset += bodyoffset; } request->send_buffer = buffer; request->total_length = offset; return; }
/********************************************************************* * * Function : is_untrusted_url * * Description : Should we "distrust" this URL (and block it)? * * Yes if it matches a line in the trustfile, or if the * referrer matches a line starting with "+" in the * trustfile. * No otherwise. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : 0 => trusted, 1 => untrusted * *********************************************************************/ int is_untrusted_url(struct client_state *csp) { struct file_list *fl; struct block_spec *b; struct url_spec **trusted_url; struct http_request rhttp[1]; const char * referer; jb_err err; /* * If we don't have a trustlist, we trust everybody */ if (((fl = csp->tlist) == NULL) || ((b = fl->f) == NULL)) { return 0; } memset(rhttp, '\0', sizeof(*rhttp)); /* * Do we trust the request URL itself? */ for (b = b->next; b ; b = b->next) { if (url_match(b->url, csp->http)) { return b->reject; } } if (NULL == (referer = get_header_value(csp->headers, "Referer:"))) { /* no referrer was supplied */ return 1; } /* * If not, do we maybe trust its referrer? */ err = parse_http_url(referer, rhttp, csp); if (err) { return 1; } for (trusted_url = csp->config->trust_list; *trusted_url != NULL; trusted_url++) { if (url_match(*trusted_url, rhttp)) { /* if the URL's referrer is from a trusted referrer, then * add the target spec to the trustfile as an unblocked * domain and return NULL (which means it's OK). */ FILE *fp; if (NULL != (fp = fopen(csp->config->trustfile, "a"))) { char * path; char * path_end; char * new_entry = strdup("~"); string_append(&new_entry, csp->http->hostport); path = csp->http->path; if ( (path[0] == '/') && (path[1] == '~') && ((path_end = strchr(path + 2, '/')) != NULL)) { /* since this path points into a user's home space * be sure to include this spec in the trustfile. */ int path_len = path_end - path; /* save offset */ path = strdup(path); /* Copy string */ if (path != NULL) { path_end = path + path_len; /* regenerate ptr to new buffer */ *(path_end + 1) = '\0'; /* Truncate path after '/' */ } string_join(&new_entry, path); } if (new_entry != NULL) { fprintf(fp, "%s\n", new_entry); free(new_entry); } else { /* FIXME: No way to handle out-of memory, so mostly ignoring it */ log_error(LOG_LEVEL_ERROR, "Out of memory adding pattern to trust file"); } fclose(fp); } return 0; } } return 1; }
int http_transfer(UrlResource *rsrc) { FILE *out = NULL; Url *u = NULL; Url *proxy_url = NULL; Url *redir_u = NULL; char *request = NULL; char *raw_header = NULL; HttpHeader *header = NULL; char *len_string = NULL; char *new_location = NULL; char buf[BUFSIZE]; int sock = 0; ssize_t bytes_read = 0; int retval = 0; int i; /* make sure we haven't recursed too much */ if( redirect_count > REDIRECT_MAX ) { report(ERR, "redirection max count exceeded " "(looping redirect?)"); redirect_count = 0; return 0; } /* make sure everything's initialized to something useful */ u = rsrc->url; if( ! *(u->host) ) { report(ERR, "no host specified"); return 0; } /* fill in proxyness */ if( !rsrc->proxy ) { rsrc->proxy = get_proxy("HTTP_PROXY"); } if( !rsrc->outfile ) { if( u->file ) rsrc->outfile = strdup(u->file); else rsrc->outfile = strdup("index.html"); } if( !u->path ) u->path = strdup("/"); if( !u->file ) u->file = strdup(""); /* funny looking */ if( !u->port ) u->port = 80; rsrc->options |= default_opts; /* send the request to either the proxy or the remote host */ if( rsrc->proxy ) { proxy_url = url_new(); url_init(proxy_url, rsrc->proxy); if( !proxy_url->port ) proxy_url->port = 80; if( !proxy_url->host ) { report(ERR, "bad proxy `%s'", rsrc->proxy); return 0; } if( proxy_url->username ) rsrc->proxy_username = strdup(proxy_url->username); if( proxy_url->password ) rsrc->proxy_password = strdup(proxy_url->password); /* Prompt for proxy password if not specified */ if( proxy_url->username && !proxy_url->password ) { char *prompt = NULL; prompt = strconcat("Password for proxy ", proxy_url->username, "@", proxy_url->host, ": ", NULL); proxy_url->password = strdup(getpass(prompt)); free(prompt); } if( ! (sock = tcp_connect(proxy_url->host, proxy_url->port)) ) return 0; u->path = strdup(""); u->file = strdup(u->full_url); request = get_request(rsrc); write(sock, request, strlen(request)); } else /* no proxy */ { if( ! (sock = tcp_connect(u->host, u->port)) ) return 0; request = get_request(rsrc); write(sock, request, strlen(request)); } out = open_outfile(rsrc); if( !out ) { report(ERR, "opening %s: %s", rsrc->outfile, strerror(errno)); return 0; } /* check to see if it returned a HTTP 1.x response */ memset(buf, '\0', 5); bytes_read = read(sock, buf, 8); if( bytes_read == 0 ) { close(sock); return 0; } if( ! (buf[0] == 'H' && buf[1] == 'T' && buf[2] == 'T' && buf[3] == 'P') ) { if ((rsrc->options & OPT_RESUME) && rsrc->outfile_offset) { report(WARN, "server does not support resume, " "try again" " with -n (no resume)"); retval = 0; goto cleanup; } write(fileno(out), buf, bytes_read); } else { /* skip the header */ buf[bytes_read] = '\0'; raw_header = get_raw_header(sock); raw_header = strconcat(buf, raw_header, NULL); header = make_http_header(raw_header); if (rsrc->options & OPT_VERBOSE) { fwrite(raw_header, 1, strlen(raw_header), stderr); } /* check for redirects */ new_location = get_header_value("location", header); if (raw_header[9] == '3' && new_location ) { redir_u = url_new(); /* make sure we still send user/password along */ redir_u->username = safe_strdup(u->username); redir_u->password = safe_strdup(u->password); url_init(redir_u, new_location); rsrc->url = redir_u; redirect_count++; retval = transfer(rsrc); goto cleanup; } if (raw_header[9] == '4' || raw_header[9] == '5') { for(i = 0; raw_header[i] && raw_header[i] != '\n'; i++); raw_header[i] = '\0'; report(ERR, "HTTP error from server: %s", raw_header); retval = 0; goto cleanup; } len_string = get_header_value("content-length", header); if (len_string) rsrc->outfile_size = (off_t )atoi(len_string); if (get_header_value("content-range", header)) rsrc->outfile_size += rsrc->outfile_offset; if( (!rsrc->outfile_size) && (rsrc->options & OPT_RESUME) && !(rsrc->options & OPT_NORESUME) && rsrc->outfile_offset ) { report(WARN, "unable to determine remote file size, try again" " with -n (no resume)"); retval = 0; goto cleanup; } } if( ! dump_data(rsrc, sock, out) ) retval = 0; else retval = 1; cleanup: free_http_header(header); close(sock); fclose(out); return retval; }
/********************************************************************* * * Function : block_url * * Description : Called from `chat'. Check to see if we need to block this. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : NULL => unblocked, else HTTP block response * *********************************************************************/ struct http_response *block_url(struct client_state *csp) { #ifdef FEATURE_IMAGE_BLOCKING char *p; #endif /* def FEATURE_IMAGE_BLOCKING */ struct http_response *rsp; /* * If it's not blocked, don't block it ;-) */ if ((csp->action->flags & ACTION_BLOCK) == 0) { return NULL; } /* * Else, prepare a response */ if (NULL == (rsp = alloc_http_response())) { return cgi_error_memory(); } /* * If it's an image-url, send back an image or redirect * as specified by the relevant +image action */ #ifdef FEATURE_IMAGE_BLOCKING if (((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0) && is_imageurl(csp)) { /* determine HOW images should be blocked */ p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER]; #if 1 /* Two alternative strategies, use this one for now: */ /* and handle accordingly: */ if ((p == NULL) || (0 == strcmpic(p, "pattern"))) { rsp->body = bindup(image_pattern_data, image_pattern_length); if (rsp->body == NULL) { free_http_response(rsp); return cgi_error_memory(); } rsp->content_length = image_pattern_length; if (enlist_unique_header(rsp->headers, "Content-Type", BUILTIN_IMAGE_MIMETYPE)) { free_http_response(rsp); return cgi_error_memory(); } } else if (0 == strcmpic(p, "blank")) { rsp->body = bindup(image_blank_data, image_blank_length); if (rsp->body == NULL) { free_http_response(rsp); return cgi_error_memory(); } rsp->content_length = image_blank_length; if (enlist_unique_header(rsp->headers, "Content-Type", BUILTIN_IMAGE_MIMETYPE)) { free_http_response(rsp); return cgi_error_memory(); } } else { rsp->status = strdup("302 Local Redirect from Privoxy"); if (rsp->status == NULL) { free_http_response(rsp); return cgi_error_memory(); } if (enlist_unique_header(rsp->headers, "Location", p)) { free_http_response(rsp); return cgi_error_memory(); } } #else /* Following code is disabled for now */ /* and handle accordingly: */ if ((p == NULL) || (0 == strcmpic(p, "pattern"))) { p = CGI_PREFIX "send-banner?type=pattern"; } else if (0 == strcmpic(p, "blank")) { p = CGI_PREFIX "send-banner?type=blank"; } rsp->status = strdup("302 Local Redirect from Privoxy"); if (rsp->status == NULL) { free_http_response(rsp); return cgi_error_memory(); } if (enlist_unique_header(rsp->headers, "Location", p)) { free_http_response(rsp); return cgi_error_memory(); } #endif /* Preceeding code is disabled for now */ } else #endif /* def FEATURE_IMAGE_BLOCKING */ /* * Else, generate an HTML "blocked" message: */ { jb_err err; struct map * exports; /* * Workaround for stupid Netscape bug which prevents * pages from being displayed if loading a referenced * JavaScript or style sheet fails. So make it appear * as if it succeeded. */ if ( NULL != (p = get_header_value(csp->headers, "User-Agent:")) && !strncmpic(p, "mozilla", 7) /* Catch Netscape but */ && !strstr(p, "Gecko") /* save Mozilla, */ && !strstr(p, "compatible") /* MSIE */ && !strstr(p, "Opera")) /* and Opera. */ { rsp->status = strdup("200 Request for blocked URL"); } else { rsp->status = strdup("404 Request for blocked URL"); } if (rsp->status == NULL) { free_http_response(rsp); return cgi_error_memory(); } exports = default_exports(csp, NULL); if (exports == NULL) { free_http_response(rsp); return cgi_error_memory(); } #ifdef FEATURE_FORCE_LOAD err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1); if (csp->http->ssl != 0) #endif /* ndef FEATURE_FORCE_LOAD */ { err = map_block_killer(exports, "force-support"); } if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1); if (!err) err = map(exports, "hostport", 1, html_encode(csp->http->hostport), 0); if (!err) err = map(exports, "path", 1, html_encode(csp->http->path), 0); if (!err) err = map(exports, "path-ue", 1, url_encode(csp->http->path), 0); if (err) { free_map(exports); free_http_response(rsp); return cgi_error_memory(); } err = template_fill_for_cgi(csp, "blocked", exports, rsp); if (err) { free_http_response(rsp); return cgi_error_memory(); } } return finish_http_response(rsp); }
int http_transfer(UrlResource *rsrc, libnet_callback notify) { FILE *out = NULL; Url *u = NULL; Url *proxy_url = NULL; Url *redir_u = NULL; char *request = NULL; //char *raw_header = NULL; HttpHeader *header = NULL; //char *len_string = NULL; //char *new_location = NULL; char *tmp_string = NULL; //char buf[BUFSIZE]; int sock = -1; ssize_t bytes_read = 0; int msg_code = 0; int retval = 0; int i; char *buf = MALLOC(BUFSIZE); if (!buf) { LIBNET_DEBUG("No enough memory!\n"); return 0; } /* make sure we haven't recursed too much */ if ( redirect_count > REDIRECT_MAX ) { LIBNET_DEBUG("redirection max count exceeded (looping redirect?)"); redirect_count = 0; msg_code = -NET_ERR_CONNECT_FAILED; goto cleanup; } /* make sure everything's initialized to something useful */ u = rsrc->url; if ( !u->host ) { LIBNET_DEBUG("no host specified"); msg_code = -NET_ERR_CONNECT_FAILED; goto cleanup; } /* fill in proxyness */ if ( !rsrc->proxy ) { rsrc->proxy = get_proxy("HTTP_PROXY"); } if (( NULL == rsrc->outfile ) && (NULL == rsrc->buffer)) { if ( u->file ) rsrc->outfile = strdup(u->file); else rsrc->outfile = strdup("index.html"); } if ( !u->path ) u->path = strdup("/"); if ( !u->file ) u->file = strdup(""); /* funny looking */ if ( !u->port ) u->port = 80; rsrc->options |= default_opts; /* send the request to either the proxy or the remote host */ if ( rsrc->proxy ) { proxy_url = url_new(); url_init(proxy_url, rsrc->proxy); if ( !proxy_url->port ) proxy_url->port = 80; if ( !proxy_url->host ) { LIBNET_DEBUG( "bad proxy `%s'", rsrc->proxy); msg_code = -NET_ERR_CONNECT_FAILED; goto cleanup; } if ( proxy_url->username ) rsrc->proxy_username = strdup(proxy_url->username); if ( proxy_url->password ) rsrc->proxy_password = strdup(proxy_url->password); #ifdef LIB_W5300 sock = w5300_tcp_connect(proxy_url->host, proxy_url->port, rsrc->srcip, rsrc->srcport); #else sock = util_tcp_connect(proxy_url->host, proxy_url->port); #endif if (sock < 0) { msg_code = -NET_ERR_CONNECT_FAILED; goto cleanup; } safe_free(u->path); safe_free(u->file); u->path = strdup(""); u->file = strdup(u->full_url); request = get_request(rsrc); LIBNET_DEBUG("sending request:\n%s", request); S_WRITE(sock, request, STRLEN(request)); FREE(request); } else /* no proxy */ { #ifdef LIB_W5300 sock = w5300_tcp_connect(u->host, u->port, rsrc->srcip, rsrc->srcport); #else sock = util_tcp_connect(u->host, u->port); #endif if (sock < 0) { msg_code = -NET_ERR_CONNECT_FAILED; goto cleanup; } request = get_request(rsrc); LIBNET_DEBUG("sending request:\n%s", request); S_WRITE(sock, request, STRLEN(request)); FREE(request); } if (rsrc->outfile) { if ((get_file_size(rsrc->outfile) > 0) && (rsrc->options & OPT_RESUME)) out = fopen(rsrc->outfile, "rb+"); else out = fopen(rsrc->outfile, "wb"); if ( !out ) { LIBNET_DEBUG( "opening %s: %s", rsrc->outfile, ""); msg_code = -NET_ERR_FILE_SAVE_ERROR; goto cleanup; } } /* check to see if it returned a HTTP 1.x response */ MEMSET(buf, '\0', 5); #ifdef LIB_W5300 bytes_read = S_READ(sock, buf, BUFSIZE); buf[bytes_read] = '\0'; LIBNET_DEBUG("receive respond:(%d)\n%s", bytes_read, buf); #else bytes_read = S_READ(sock, buf, 8); #endif if ( bytes_read <= 0 ) { msg_code = -NET_ERR_HTTP_SERVER_ERROR; goto cleanup; } if ( ! (buf[0] == 'H' && buf[1] == 'T' && buf[2] == 'T' && buf[3] == 'P') ) { if((rsrc->options & OPT_RESUME) && rsrc->outfile_offset) { LIBNET_DEBUG("server does not support resume!"); msg_code = -NET_ERR_OPERATION_NOT_PERMIT; goto cleanup; } //fwrite(buf, bytes_read, 1,out); } else { /* skip the header */ #ifdef LIB_W5300 buf[bytes_read] = '\0'; #else char *raw_header1 = NULL; buf[bytes_read] = '\0'; raw_header1 = get_raw_header(sock); strconcat2(buf, raw_header1, NULL); FREE(raw_header1); LIBNET_DEBUG("receive respond:(%d)\n%s", bytes_read, buf); #endif header = make_http_header(buf); /* check for redirects */ tmp_string = get_header_value("location", header); if (buf[9] == '3' && tmp_string ) { #if 1 //diable redirec function redir_u = url_new(); /* make sure we still send user/password along */ redir_u->username = safe_strdup(u->username); redir_u->password = safe_strdup(u->password); url_init(redir_u, tmp_string); rsrc->url = redir_u; redirect_count++; //retval = transfer(rsrc, notify); transfer((UINT32)rsrc, (UINT32)notify); rsrc->url =u; redirect_count--; if(redirect_count<0) redirect_count=0; if (redir_u) { url_destroy(redir_u); FREE(redir_u); } #endif FREE(tmp_string); tmp_string = NULL; //msg_code = -NET_ERR_OPERATION_NOT_PERMIT;//we can support redirect now, remove this line. goto cleanup; } if (tmp_string) { FREE(tmp_string); tmp_string = NULL; } if (buf[9] == '4' || buf[9] == '5') { for (i = 0; buf[i] && buf[i] != '\n'; i++); buf[i] = '\0'; LIBNET_DEBUG("HTTP error from server: %s\n", buf); if( buf[9] == '4' && buf[10] == '0' && buf[11] == '4') msg_code = -NET_ERR_FILE_NOT_FOUND; else msg_code = -NET_ERR_HTTP_SERVER_ERROR; goto cleanup; } tmp_string = get_header_value("content-length", header); if (tmp_string) { rsrc->outfile_size = (off_t )ATOI(tmp_string); FREE(tmp_string); tmp_string = NULL; if(rsrc->use_pecache ==0) { if ((rsrc->buffer) && (rsrc->buffer_len < rsrc->outfile_size)) { LIBNET_DEBUG("the buffer length less than the file fize (%d < %d)\n", rsrc->buffer, (int)rsrc->outfile_size); msg_code = -NET_ERR_FILE_SAVE_ERROR; goto cleanup; } } } tmp_string = get_header_value("content-range", header); if (tmp_string) { FREE(tmp_string); tmp_string = NULL; rsrc->outfile_size += rsrc->outfile_offset; } if ((!rsrc->outfile_size) && (rsrc->options & OPT_RESUME) && !(rsrc->options & OPT_NORESUME) && rsrc->outfile_offset ) { LIBNET_DEBUG("unable to determine remote file size"); msg_code = -NET_ERR_FILE_SAVE_ERROR; goto cleanup; } } if(rsrc->use_pecache ==0) retval = dump_data(rsrc, sock, out, notify); else retval = dump_data_to_pecache(rsrc, sock, out, notify); cleanup: free_http_header(header); //if (raw_header) // FREE(raw_header); if (proxy_url) { url_destroy(proxy_url); FREE(proxy_url); } if (sock >= 0) { S_CLOSE(sock); } if (out) fclose(out); if (buf) { FREE(buf); } #ifndef WIN32 if (rsrc->outfile) fs_sync(rsrc->outfile); #endif if (msg_code < 0 && rsrc->running) { notify(NET_MSG_DOWNLOAD_FINISH, (UINT32)msg_code); libnet_abort_url_read(TRUE);//to break url_open while loop //retval!=1 means transfer fail } return retval; }
void * http_go_proc(task_t *t) { int index = TASK_THRINDEX(t); Request h; ArgumentList prefs; userkey k; HTTP_Status result; DistillerStatus dist_result; const char *content_type; Argument *arg; int thresh; gm_Bool no_distill = gm_False; gm_Bool is_text_html = gm_False; #ifdef LOGGING struct loginfo lo; char logmsg[MAX_LOGMSG_LEN]; #endif /* LOGGING */ /* * New task data should be the request structure. */ init_Request(&h); h.cli_fd = (int)TASK_DATA(t); /* socket FD of client */ SET_TASK_DATA(t,&h); INST_begin_timestamp(index); INST_set_size(index,0); INST_set_thread_state(index, THR_ACCEPTED); INST_timestamp(index, m_arrival); #ifdef LOGGING LOGGING_init_loginfo(&lo); h.lo = &lo; #endif /* LOGGING */ /* * this should read all the headers. */ if (TASK_METADATA(t) == NULL) { int result; assert( DistillerBufferAlloc(&h.cli_hdrs, PERF_HTTP_TOTAL_HEADERLEN) == gm_True); result = readline_or_timeout(&h, READ_ALL_HEADERS, NULL); INST_timestamp(index, m_headersdone); if (result == -1) { /* client request timed out, or error reading hdrs */ /* TC::1 client timeout, or request doesn't sanity check */ goto HTTPGO_FINISH; /* NOTREACHED */ } } else { #ifdef NEWFE /* * This task is a child of a previous */ strncpy(h.cli_hdrs.mime_headers, TASK_METADATA(t), PERF_HTTP_TOTAL_HEADERLEN-1); FREE(TASK_METADATA(t)); #endif /* NEWFE */ } /* parse the headers and request line, filling them in to the loginfo */ result = parse_status_and_headers(&h); if (result != HTTP_NO_ERR) { /* BUG:: last arg of http_error_return should be a substitution arg */ /* TC::2 parse_status_and_headers returns an error */ http_error_return(&h, result); printf("Error occured here!\n"); goto HTTPGO_FINISH; } /* * We have a reasonable looking request. Get prefs for this user. */ k = userkey_from_sock_ipaddr(h.cli_fd); #ifdef LOGGING lo.ipaddr = k; #endif /* LOGGING */ (void)get_userprefs(k, &prefs); /* * Extract any arguments embedded in the URL itself, and add them * to the arg list. * TC::3 url is magic vs nonmagic */ if (is_magic ((char *) h.url)) { /* demagifying a url will never lengthen it so this is a good * upper bounds on the length of the non magical url */ char *demagicURL = ALLOCA(strlen(h.url)+1); assert(demagicURL); strcpy(demagicURL, h.url); from_magic((char *) demagicURL, h.url, &prefs); } /* determine the threshold for bypassing */ arg = getArgumentFromIdInList(&prefs, FRONT_MTU); thresh = (arg == NULL ? PERF_FRONT_MTU : ARG_INT(*arg)); /* determine if distillation is turned off for this * request. EXCEPTION: Force distillation for Prefs html form. */ arg = getArgumentFromIdInList(&prefs, FRONT_NO_DISTILL); if (arg != NULL && ARG_INT(*arg) && strcasecmp(fe_get_prefs_url, h.url) != 0) { /* TC::4 no_distill is set */ no_distill = gm_True; } else { no_distill = gm_False; } /* Short-circuit the following special URL's: * - "set my prefs as follows" (e.g. form submission) */ if (is_setpref_url(h.url)) { /* * handle what send user prefs form sends back. * TC::5 is_setpref_url returns true */ result = parse_and_change_prefs(h.url, k, h.errmsg); if (result == HTTP_NO_ERR) { /* TC::5.1 setpref url succeeds in setting prefs */ correct_write(h.cli_fd, "HTTP/1.0 200\r\nContent-type: text/html\r\n\r\n", -1); correct_write(h.cli_fd, "<html><head><title>Preferences Set</title></head>" "<body><center><h1>Preferences set</h1>" "Your new preferences have been set. Press the back " "button twice to resume browsing." "<p></center></body></html>", -1); } else { /* TC::5.2 setpref url fails in setting prefs */ http_error_return(&h, result); } } else if (is_getpref_url(h.url)) { /* TC::6 gimme my prefs*/ send_prefs(&prefs, h.cli_fd); } else if (is_server_url(h.url)==gm_False && strcasecmp(h.method, "get") != 0 && strcasecmp(h.method, "post") != 0) { /* * Doesn't appear to be an HTTP GET or POST request; so act as a * "dumb tunnel" for passing the request to the server (actually, via * the cache) and relaying the result to the client. */ /* TC::7 tunnel */ proxy_debug_3(DBG_HTTP, "Tunneling '%s'", DistillerBufferData(&h.cli_hdrs)); INST_set_thread_state(index, THR_DISTILLERSEND); tunnel(&h); } else { /* * It's not a special URL, and the request appears to be a GET/POST. * Add in the client's IP address as an INT32 argument so that * the distiller driver can get at it. */ SET_ARG_INT(prefs.arg[prefs.nargs], (INT32) k); SET_ARG_ID(prefs.arg[prefs.nargs], FRONT_CLIENT_IP); prefs.nargs++; result = server_dispatch(&prefs, t); /* * If we get a transport-level error (i.e. fetch from cache failed * due to an internal cache error), wrap the error in HTML (if * needed) and return error to user. * Otherwise, if the transaction succeeded but the server return * code indicates failure (i.e. != 200), **OR** if the server data * is smaller than a threshold size, bypass the server data * directly to the client. * Otherwise, attempt to distill. */ if (result != HTTP_NO_ERR) { /* transport level error: wrap in HTML for delivery to user */ /* TC::8 server_dispatch returns transport level error */ http_error_return(&h, result); goto HTTPGO_FINISH; } content_type = get_header_value(&h.svr_hdrs, "content-type", NULL, NULL, NULL); if (content_type == NULL) { /* TC::9 content-type can't be deduced */ content_type = "application/octet-stream"; } is_text_html = ( ((strncasecmp(content_type, "text/html", 9) == 0) || (strncasecmp(content_type, "text/plain", 10) == 0)) ? gm_True : gm_False); /*if ( (*h.url != '/' && strncasecmp(h.url, fe_agg_string, strlen(fe_agg_string)) != 0) &&*/ /* bypass ONLY if it is not a server-type URL */ /* TC::10.1 bypass because non-200s status */ /* TC::10.2 bypass because not text/html and too small to distill */ /* TC::4 bypass because no_distill is set */ /* bypass server data directly to user */ if ( is_server_url(h.url)==gm_False) { char *bypass_reason = NULL; if (h.svr_http_status != 200) { bypass_reason = "201 Non-OK server status"; } else if (is_text_html == gm_False && DistillerBufferLength(&h.svr_data) <= thresh) { bypass_reason = "202 content-type not text/html and content-length too short"; } else if (no_distill == gm_True) { bypass_reason = "203 distillation not indicated"; } if (bypass_reason) { INST_set_thread_state(index, THR_WRITEBACK); /* * Set return headers to indicate why the bypass occurred. */ insert_header(&h.svr_hdrs, TRANSEND_STATUS_HEADER, bypass_reason, 0); complete_bypass(&h); goto HTTPGO_FINISH; } } /* all is well: continue by dispatching to a worker for distillation */ dist_result = proxy_dispatch(&prefs, t); switch(dist_result) { case distOk: /* TC::11 distillation succeeded */ INST_timestamp(index, m_wbstart); insert_header(&h.pxy_hdrs, TRANSEND_STATUS_HEADER, "200 distillation OK", 0); correct_write(h.cli_fd, (char *)DistillerBufferData(&h.pxy_hdrs), (int)DistillerBufferLength(&h.pxy_hdrs)); /* -1 to avoid NULL term gunk */ correct_write(h.cli_fd, (char *)DistillerBufferData(&h.pxy_data), (int)DistillerBufferLength(&h.pxy_data)); INST_timestamp(thrindex, m_wbdone); break; case distDistillerNotFound: case distLaunchTimeout: case distBadInput: case distConnectionBroken: /* forward original if distiller for this type not found, connection repeatedly broken, or couldn't be launched */ /* TC::12 bypass because distillation failed */ insert_header(&h.svr_hdrs, (dist_result == distBadInput ? TRANSEND_STATUS_HEADER : TRANSEND_ERROR_HEADER), FE_getDistillerStatusString(dist_result), 0); if ((arg = getArgumentFromIdInList(&prefs, FRONT_DEVELOPER)) && ARG_INT(*arg)) { /* return explicit error message */ int tmp_len = snprintf(h.errmsg, HTTP_ERRMSG_MAX, "<i>[set arg <tt>i%d</tt> to 0 to suppress " "this diagnostic]</i><br>", FRONT_DEVELOPER); strncat(h.errmsg, FE_getDistillerStatusString(dist_result), HTTP_ERRMSG_MAX - tmp_len - 1); http_error_return(&h, HTTP_ERR_UNSPECIFIED); } else { /*if (*h.url == '/' || strncasecmp(h.url, fe_agg_string, strlen(fe_agg_string)) == 0) {*/ if (is_server_url(h.url)==gm_True) { /* this is a URL in the frontend's namespace, or an aggregator URL */ strcpy(h.errmsg, h.url); http_error_return(&h, HTTP_ERR_AGGREGATOR_ERROR); } else { complete_bypass(&h); } } break; case distRedispatch: /* * Redispatch count expired: too many redispatches (probably indicates * infinite loop in redispatch route.) */ snprintf(h.errmsg, HTTP_ERRMSG_MAX, "%d", PERF_REQUEST_TTL); http_error_return(&h, HTTP_ERR_ROUTING_ERROR); break; default: /* TC::13 some other distillation error */ insert_header(&h.svr_hdrs, TRANSEND_STATUS_HEADER, FE_getDistillerStatusString(dist_result), 0); http_error_return(&h, HTTP_ERR_UNSPECIFIED); break; } /* switch(dist_result) */ } /* if...else...else...endif */ /* all cases exit through this single exit point */ HTTPGO_FINISH: free_Request(&h); INST_timestamp(index, m_wbdone); INST_end_timestamp(index); if (TASK_PARENT(t) == 0 && TASK_CHILD_INDEX(t) == 0) { /* this is a "root task" */ close(h.cli_fd); } #ifdef LOGGING /* log the request info */ /* BUG::relies on formatting of the userkey */ /* I compare the IP address to 127.0.0.1 so that I don't log connections from localhost, namely the fe_check script. I also MD5 the IP address. */ k = lo.ipaddr; if (((UINT32) k) != ((UINT32) htonl(0x7F000001))) { /* MD5_CTX theHash; UINT32 res; MD5Init(&theHash); MD5Update(&theHash, magicKey, sizeof(magicKey)); MD5Update(&theHash, &k, sizeof(UINT32)); MD5Final(&theHash); memcpy(&res, theHash.digest, sizeof(UINT32)); res = ntohl(res); snprintf(logmsg, MAX_LOGMSG_LEN-1, "(HTTP) %lu %lu \"%s\" %d %ld %ld\n", res, lo.date, lo.url, lo.http_response, lo.size_before, lo.size_after);*/ snprintf(logmsg, MAX_LOGMSG_LEN-1, "(HTTP) %08x %08x \"%s\" %d %ld %ld\n", (UINT32) k, lo.date, lo.url, lo.http_response, lo.size_before, lo.size_after); gm_log(logmsg); } #endif /* LOGGING */ return (void *)0; }
/* * Function Name: validate_session_policy * This is the NSAPI directive funtion which gets called for each request * It does session validation and policy check for each request. * Input: As defined by a SAF * Output: As defined by a SAF */ NSAPI_PUBLIC int validate_session_policy(pblock *param, Session *sn, Request *rq) { const char *thisfunc = "validate_session_policy()"; char *dpro_cookie = NULL; am_status_t status = AM_SUCCESS; int requestResult = REQ_ABORTED; int notifResult = REQ_ABORTED; const char *ruser = NULL; am_map_t env_parameter_map = NULL; am_policy_result_t result = AM_POLICY_RESULT_INITIALIZER; void *args[] = { (void *)rq }; char *request_url = NULL; char *orig_req = NULL ; char *response = NULL; char *clf_req = NULL; char *server_protocol = NULL; void *agent_config = NULL; char *logout_url = NULL; char *uri_hdr = NULL; char *pathInfo_hdr = NULL; char *method_hdr = NULL; char *method = NULL; char *virtHost_hdr = NULL; char *query_hdr = NULL; char *query = NULL; char *protocol = "HTTP"; const char *clientIP_hdr_name = NULL; char *clientIP_hdr = NULL; char *clientIP = NULL; const char *clientHostname_hdr_name = NULL; char *clientHostname_hdr = NULL; char *clientHostname = NULL; am_status_t cdStatus = AM_FAILURE; // check if agent is initialized. // if not initialized, then call agent init function // This needs to be synchronized as only one time agent // initialization needs to be done. if(agentInitialized != B_TRUE){ //Start critical section crit_enter(initLock); if(agentInitialized != B_TRUE){ am_web_log_debug("%s: Will call init.", thisfunc); init_at_request(); if(agentInitialized != B_TRUE){ am_web_log_error("%s: Agent is still not intialized", thisfunc); //deny the access requestResult = do_deny(sn, rq, status); status = AM_FAILURE; } else { am_web_log_debug("%s: Agent intialized"); } } //end critical section crit_exit(initLock); } if (status == AM_SUCCESS) { // Get the agent configuration agent_config = am_web_get_agent_configuration(); // Dump the entire set of request headers if (am_web_is_max_debug_on()) { char *header_str = pblock_pblock2str(rq->reqpb, NULL); am_web_log_max_debug("%s: Headers: %s", thisfunc, header_str); system_free(header_str); } } // Get header values if (status == AM_SUCCESS) { status = get_header_value(rq->reqpb, REQUEST_URI, B_TRUE, &uri_hdr, B_FALSE, NULL); } if (status == AM_SUCCESS) { status = get_header_value(rq->vars, PATH_INFO, B_FALSE, &pathInfo_hdr, B_FALSE, NULL); } if (status == AM_SUCCESS) { status = get_header_value(rq->reqpb, REQUEST_METHOD, B_TRUE, &method_hdr, B_TRUE, &method); } if (status == AM_SUCCESS) { status = get_header_value(rq->headers, "ampxy_host", B_TRUE, &virtHost_hdr, B_FALSE, NULL); } if (status == AM_SUCCESS) { status = get_header_value(rq->reqpb, REQUEST_QUERY, B_FALSE, &query_hdr, B_TRUE, &query); } if (security_active) { protocol = "HTTPS"; } // Get the request URL if (status == AM_SUCCESS) { if (am_web_is_proxy_override_host_port_set(agent_config) == AM_FALSE) { status = am_web_get_request_url(virtHost_hdr, protocol, NULL, 0, uri_hdr, query, &request_url, agent_config); if(status == AM_SUCCESS) { am_web_log_debug("%s: Request_url: %s", thisfunc, request_url); } else { am_web_log_error("%s: Could not get the request URL. " "Failed with error: %s.", thisfunc, am_status_to_string(status)); } } } if (status == AM_SUCCESS) { if (am_web_is_proxy_override_host_port_set(agent_config) == AM_TRUE) { const char *agent_host = am_web_get_agent_server_host(agent_config); int agent_port = am_web_get_agent_server_port(agent_config); if (agent_host != NULL) { char *temp = NULL; temp = replace_host_port(request_url, agent_host, agent_port, agent_config); if (temp != NULL) { free(request_url); request_url = temp; } } am_web_log_debug("%s: Request_url after overriding " "host and port: %s", thisfunc, request_url); } } if (status == AM_SUCCESS) { // Check for magic notification URL if (B_TRUE == am_web_is_notification(request_url, agent_config)) { am_web_free_memory(request_url); am_web_delete_agent_configuration(agent_config); if(query != NULL) { free(query); query = NULL; } if(method != NULL) { free(method); method = NULL; } return REQ_PROCEED; } } // Check if the SSO token is in the cookie header if (status == AM_SUCCESS) { requestResult = getISCookie(pblock_findval(COOKIE_HDR, rq->headers), &dpro_cookie, agent_config); if (requestResult == REQ_ABORTED) { status = AM_FAILURE; } else if (dpro_cookie != NULL) { am_web_log_debug("%s: SSO token found in cookie header.", thisfunc); } } // Create the environment map if( status == AM_SUCCESS) { status = am_map_create(&env_parameter_map); if( status != AM_SUCCESS) { am_web_log_error("%s: Unable to create map, status = %s (%d)", thisfunc, am_status_to_string(status), status); } } // If there is a proxy in front of the agent, the user can set in the // properties file the name of the headers that the proxy uses to set // the real client IP and host name. In that case the agent needs // to use the value of these headers to process the request // // Get the client IP address header set by the proxy, if there is one if (status == AM_SUCCESS) { clientIP_hdr_name = am_web_get_client_ip_header_name(agent_config); if (clientIP_hdr_name != NULL) { status = get_header_value(rq->headers, clientIP_hdr_name, B_FALSE, &clientIP_hdr, B_FALSE, NULL); } } // Get the client host name header set by the proxy, if there is one if (status == AM_SUCCESS) { clientHostname_hdr_name = am_web_get_client_hostname_header_name(agent_config); if (clientHostname_hdr_name != NULL) { status = get_header_value(rq->headers, clientHostname_hdr_name, B_FALSE, &clientHostname_hdr, B_FALSE, NULL); } } // If the client IP and host name headers contain more than one // value, take the first value. if (status == AM_SUCCESS) { if ((clientIP_hdr != NULL) || (clientHostname_hdr != NULL)) { status = am_web_get_client_ip_host(clientIP_hdr, clientHostname_hdr, &clientIP, &clientHostname); } } // Set the IP address and host name in the environment map if ((status == AM_SUCCESS) && (clientIP != NULL)) { status = am_web_set_host_ip_in_env_map(clientIP, clientHostname, env_parameter_map, agent_config); } // If the client IP was not obtained previously, // get it from the REMOTE_ADDR header. if ((status == AM_SUCCESS) && (clientIP == NULL)) { status = get_header_value(sn->client, REQUEST_IP_ADDR, B_FALSE, &clientIP_hdr, B_TRUE, &clientIP); } // In CDSSO mode, check if the sso token is in the post data if( status == AM_SUCCESS) { if((am_web_is_cdsso_enabled(agent_config) == B_TRUE) && (strcmp(method, REQUEST_METHOD_POST) == 0)) { if((dpro_cookie == NULL) && (am_web_is_url_enforced(request_url, pathInfo_hdr, clientIP, agent_config) == B_TRUE)) { // Set original method to GET orig_req = strdup(REQUEST_METHOD_GET); if (orig_req != NULL) { am_web_log_debug("%s: Request method set to GET.", thisfunc); } else { am_web_log_error("%s: Not enough memory to ", "allocate orig_req.", thisfunc); status = AM_NO_MEMORY; } // Check if dpro_cookie is in post data if( status == AM_SUCCESS) { response = get_post_assertion_data(sn, rq, request_url); status = am_web_check_cookie_in_post(args, &dpro_cookie, &request_url, &orig_req, method, response, B_FALSE, set_cookie, set_method, agent_config); if( status == AM_SUCCESS) { am_web_log_debug("%s: SSO token found in " "assertion.",thisfunc); } else { am_web_log_debug("%s: SSO token not found in " "assertion. Redirecting to login page.", thisfunc); status = AM_INVALID_SESSION; } } // Set back the original clf-request attribute if (status == AM_SUCCESS) { int clf_reqSize = 0; if ((query != NULL) && (strlen(query) > 0)) { clf_reqSize = strlen(orig_req) + strlen(uri_hdr) + strlen (query) + strlen(protocol) + 4; } else { clf_reqSize = strlen(orig_req) + strlen(uri_hdr) + strlen(protocol) + 3; } clf_req = malloc(clf_reqSize); if (clf_req == NULL) { am_web_log_error("%s: Unable to allocate %i " "bytes for clf_req", thisfunc, clf_reqSize); status = AM_NO_MEMORY; } else { memset (clf_req,'\0',clf_reqSize); strcpy(clf_req, orig_req); strcat(clf_req, " "); strcat(clf_req, uri_hdr); if ((query != NULL) && (strlen(query) > 0)) { strcat(clf_req, "?"); strcat(clf_req, query); } strcat(clf_req, " "); strcat(clf_req, protocol); am_web_log_debug("%s: clf-request set to %s", thisfunc, clf_req); } pblock_nvinsert(REQUEST_CLF, clf_req, rq->reqpb); } } } } // Check if access is allowed. if( status == AM_SUCCESS) { if (dpro_cookie != NULL) { am_web_log_debug("%s: SSO token = %s", thisfunc, dpro_cookie); } else { am_web_log_debug("%s: SSO token not found.", thisfunc); } status = am_web_is_access_allowed(dpro_cookie, request_url, pathInfo_hdr, method, clientIP, env_parameter_map, &result, agent_config); am_map_destroy(env_parameter_map); } switch(status) { case AM_SUCCESS: // Set remote user and authentication type ruser = result.remote_user; if (ruser != NULL) { pb_param *pbuser = pblock_remove(AUTH_USER_VAR, rq->vars); pb_param *pbauth = pblock_remove(AUTH_TYPE_VAR, rq->vars); if (pbuser != NULL) { param_free(pbuser); } pblock_nvinsert(AUTH_USER_VAR, ruser, rq->vars); if (pbauth != NULL) { param_free(pbauth); } pblock_nvinsert(AUTH_TYPE_VAR, AM_WEB_AUTH_TYPE_VALUE, rq->vars); am_web_log_debug("%s: access allowed to %s", thisfunc, ruser); } else { am_web_log_debug("%s: Remote user not set, " "allowing access to the url as it is in not " "enforced list", thisfunc); } if (am_web_is_logout_url(request_url, agent_config) == B_TRUE) { (void)am_web_logout_cookies_reset(reset_cookie, args, agent_config); } // set LDAP user attributes to http header status = am_web_result_attr_map_set(&result, set_header, set_cookie_in_response, set_header_attr_as_cookie, get_cookie_sync, args, agent_config); if (status != AM_SUCCESS) { am_web_log_error("%s: am_web_result_attr_map_set failed, " "status = %s (%d)", thisfunc, am_status_to_string(status), status); requestResult = REQ_ABORTED; } else { requestResult = REQ_PROCEED; } break; case AM_ACCESS_DENIED: am_web_log_debug("%s: Access denied to %s", thisfunc, result.remote_user ? result.remote_user : "******"); requestResult = do_redirect(sn, rq, status, &result, request_url, method, agent_config); break; case AM_INVALID_SESSION: if (am_web_is_cdsso_enabled(agent_config) == B_TRUE) { cdStatus = am_web_do_cookie_domain_set(set_cookie, args, EMPTY_STRING, agent_config); if(cdStatus != AM_SUCCESS) { am_web_log_error("%s: CDSSO reset cookie failed", thisfunc); } } am_web_do_cookies_reset(reset_cookie, args, agent_config); requestResult = do_redirect(sn, rq, status, &result, request_url, method, agent_config); break; case AM_INVALID_FQDN_ACCESS: // Redirect to self with correct FQDN - no post preservation requestResult = do_redirect(sn, rq, status, &result, request_url, method, agent_config); break; case AM_REDIRECT_LOGOUT: status = am_web_get_logout_url(&logout_url, agent_config); if(status == AM_SUCCESS) { do_url_redirect(sn,rq,logout_url); } else { requestResult = REQ_ABORTED; am_web_log_debug("validate_session_policy(): " "am_web_get_logout_url failed. "); } break; case AM_INVALID_ARGUMENT: case AM_NO_MEMORY: default: am_web_log_error("validate_session_policy() Status: %s (%d)", am_status_to_string(status), status); requestResult = REQ_ABORTED; break; } // Cleaning am_web_clear_attributes_map(&result); am_policy_result_destroy(&result); am_web_free_memory(dpro_cookie); am_web_free_memory(request_url); am_web_free_memory(logout_url); am_web_delete_agent_configuration(agent_config); if (orig_req != NULL) { free(orig_req); orig_req = NULL; } if (response != NULL) { free(response); response = NULL; } if (clf_req != NULL) { free(clf_req); clf_req = NULL; } if(query != NULL) { free(query); query = NULL; } if(method != NULL) { free(method); method = NULL; } if(clientIP != NULL) { am_web_free_memory(clientIP); } if(clientHostname != NULL) { am_web_free_memory(clientHostname); } am_web_log_max_debug("%s: Completed handling request with status: %s.", thisfunc, am_status_to_string(status)); return requestResult; }
void build_environ_header(conn_obj* objp){ char *hdr_value; char *path_info; char *query_str; char *tmp; request_obj *req_objp; tmp=NULL; req_objp=objp->req_objp; path_info=req_objp->uri+strlen("/cgi"); query_str=strchr(req_objp->uri,'?'); query_str=query_str==NULL?query_str:query_str+1; hdr_value=get_header_value(req_objp->header_list,"Content-Length"); add_tail(objp->environ_list,create_environ_header("CONTENT_LENGTH",hdr_value)); hdr_value=get_header_value(req_objp->header_list,"Content-Type"); add_tail(objp->environ_list,create_environ_header("CONTENT_TYPE",hdr_value)); add_tail(objp->environ_list,create_environ_header("GATEWAY_INTERFACE","CGI/1.1")); add_tail(objp->environ_list,create_environ_header("REQUEST_URI",req_objp->uri)); add_tail(objp->environ_list,create_environ_header("PATH_INFO",path_info)); add_tail(objp->environ_list,create_environ_header("QUERY_STRING",query_str)); add_tail(objp->environ_list,create_environ_header("SCRIPT_NAME","/cgi")); add_tail(objp->environ_list,create_environ_header("REMOTE_ADDR",objp->remote_addr)); switch(req_objp->mtdcode){ case GET: tmp="GET";break; case POST: tmp="POST";break; case HEAD: tmp="HEAD";break; default: break; } add_tail(objp->environ_list,create_environ_header("REQUEST_METHOD",tmp)); if(objp->protocal==HTTP){ tmp=HTTP_port_str; } else{ tmp=HTTPS_port_str; } add_tail(objp->environ_list,create_environ_header("SERVER_PORT",tmp)); add_tail(objp->environ_list,create_environ_header("SERVER_PROTOCOL","HTTP/1.1")); add_tail(objp->environ_list,create_environ_header("SERVER_SOFTWARE","Liso/1.0")); hdr_value=get_header_value(req_objp->header_list,"Accept"); add_tail(objp->environ_list,create_environ_header("HTTP_ACCEPT",hdr_value)); hdr_value=get_header_value(req_objp->header_list,"Referer"); add_tail(objp->environ_list,create_environ_header("HTTP_REFERER",hdr_value)); hdr_value=get_header_value(req_objp->header_list,"Accept-Encoding"); add_tail(objp->environ_list,create_environ_header("HTTP_ACCEPT_ENCODING",hdr_value)); hdr_value=get_header_value(req_objp->header_list,"Accept-Language"); add_tail(objp->environ_list,create_environ_header("HTTP_ACCEPT_LANGUAGE",hdr_value)); hdr_value=get_header_value(req_objp->header_list,"Accept-Charset"); add_tail(objp->environ_list,create_environ_header("HTTP_ACCEPT_CHARSET",hdr_value)); hdr_value=get_header_value(req_objp->header_list,"Host"); add_tail(objp->environ_list,create_environ_header("HTTP_HOST",hdr_value)); hdr_value=get_header_value(req_objp->header_list,"Cookie"); add_tail(objp->environ_list,create_environ_header("HTTP_COOKIE",hdr_value)); hdr_value=get_header_value(req_objp->header_list,"User-Agent"); add_tail(objp->environ_list,create_environ_header("HTTP_USER_AGENT",hdr_value)); hdr_value=get_header_value(req_objp->header_list,"Connection"); add_tail(objp->environ_list,create_environ_header("HTTP_CONNECTION",hdr_value)); }