/** * Add old IE support (Compatibility View) for POST requests by forcing a 2nd read on the * server socket, to make IE send the POST body. * Tests revealed that this mode does not change the behaviour for recent browser. Therefore, * it can be used all the time. Option -i allows to disable it. * * @return 0 if successful, -1 otherwise */ int ie_compat_read_post_body(sock_t sock, request_t* req, proxenet_ssl_context_t* sslctx) { int nb; size_t old_len, body_len; char *body, *clen; /* to speed-up, disregard requests without body */ if (strcmp(req->http_infos.method, "POST")!=0 && \ strcmp(req->http_infos.method, "PUT")!=0) return 0; /* read Content-Length header */ clen = get_header_by_name(req->data, "Content-Length: "); if (!clen){ xlog(LOG_ERROR, "%s\n", "Extending IE POST: No Content-Length"); return -1; } /* if Content-Length is zero */ body_len = (size_t)atoi(clen); proxenet_xfree(clen); if (body_len==0){ return 0; } /* if everything has already been sent (i.e. end of already received buffer is not CRLF*2) */ if (req->data[ req->size-4 ] != '\r') return 0; if (req->data[ req->size-3 ] != '\n') return 0; if (req->data[ req->size-2 ] != '\r') return 0; if (req->data[ req->size-1 ] != '\n') return 0; /* read data (if any) */ nb = proxenet_read_all(sock, &body, sslctx); if (nb<0){ xlog(LOG_ERROR, "%s\n", "Extending IE POST: failed to read"); return -1; } /* and extend the request buffer */ if (nb>0){ old_len = req->size; req->size = old_len + (size_t)nb; req->data = proxenet_xrealloc(req->data, req->size); memcpy(req->data + old_len, body, (size_t)nb); } proxenet_xfree(body); #ifdef DEBUG xlog(LOG_DEBUG, "Extending request for IE: new_size=%d (content-length=%d)\n", req->size, body_len); #endif return 0; }
/** * Modifies the HTTP request to strip out the protocol and hostname * If successful, the request will be modified on output of this function as a * valid HTTP request : * * METHOD /PATH HTTP/1.1[...] * * @return 0 if no error was encountered, -1 otherwise. */ int format_http_request(request_t* req) { size_t request_len = req->size; size_t new_request_len = 0; char **request = &req->data; char *old_ptr, *new_ptr, *ptr; unsigned int i; int offlen; switch(get_http_protocol(req)){ case HTTP: /* check that !NULL is done by get_http_protocol */ ptr = strstr(*request, HTTP_PROTO_STRING); /* -1 because of \x00 added by sizeof */ offlen = sizeof(HTTP_PROTO_STRING)-1; break; case HTTPS: ptr = strstr(*request, HTTPS_PROTO_STRING); offlen = sizeof(HTTPS_PROTO_STRING)-1; break; case WS: ptr = strstr(*request, WS_PROTO_STRING); offlen = sizeof(WS_PROTO_STRING)-1; break; case TRANSPARENT: return 0; default: return -1; } old_ptr = ptr; new_ptr = strchr(old_ptr + offlen, '/'); if (!new_ptr) { xlog(LOG_ERROR, "%s\n", "Cannot find path (must not be implicit)"); return -1; } new_request_len = request_len - (new_ptr-old_ptr); #ifdef DEBUG xlog(LOG_DEBUG, "Formatting HTTP request (%dB->%dB)\n", request_len, new_request_len); #endif for (i=0; i<new_request_len - (old_ptr-*request);i++) { *(old_ptr+i) = *(new_ptr+i); } req->data = proxenet_xrealloc(*request, new_request_len); req->size = new_request_len; return 0; }
/** * Modifies the HTTP request to strip out the protocol and hostname * If successful, the request will be modified on output of this function as a * valid HTTP request : * METHOD /PATH HTTP/1.1[...] * * @return 0 if no error was encountered, -1 otherwise. */ int format_http_request(char** request, size_t* request_len) { size_t new_request_len = 0; char *old_ptr, *new_ptr, *ptr; unsigned int i; int offlen; /* Move to beginning of URL */ for(ptr=*request; ptr && *ptr!=' ' && *ptr!='\x00'; ptr++); if(!ptr || *ptr!=' '){ xlog(LOG_ERROR, "%s\n", "HTTP request has incorrect format"); return -1; } ++ptr; if(*ptr=='/'){ /* this indicates that the request is well formed already */ /* this case would happen only when using in transparent mode */ return 0; } if( strncmp(ptr, HTTP_PROTO_STRING, sizeof(HTTP_PROTO_STRING)-1)==0 ){ offlen = sizeof(HTTP_PROTO_STRING)-1; // -1 because of \x00 added by sizeof } else if( strncmp(ptr, HTTPS_PROTO_STRING, sizeof(HTTP_PROTO_STRING)-1)==0 ){ offlen = sizeof(HTTPS_PROTO_STRING)-1; } else { xlog(LOG_ERROR, "Cannot find protocol (%s|%s) in request:\n%s\n", HTTP_STRING, HTTPS_STRING, *request); return -1; } /* here offlen > 0 */ old_ptr = ptr; new_ptr = strchr(old_ptr + offlen, '/'); if (!new_ptr) { xlog(LOG_ERROR, "%s\n", "Cannot find path (must not be implicit)"); return -1; } new_request_len = *request_len - (new_ptr-old_ptr); #ifdef DEBUG xlog(LOG_DEBUG, "Formatting HTTP request (%dB->%dB)\n", *request_len, new_request_len); #endif for (i=0; i<new_request_len - (old_ptr-*request);i++) { *(old_ptr+i) = *(new_ptr+i); } *request = proxenet_xrealloc(*request, new_request_len); *request_len = new_request_len; return 0; }
/** * Read all the data pending in the socket. * The buffer with the data is allocated by proxenet_read_all() and *MUST* be free-ed * by the caller. * * @return the number of bytes read, or -1 if an error occured */ int proxenet_read_all(sock_t sock, char** ptr, proxenet_ssl_context_t* ssl) { int ret = 0; unsigned int total_bytes_read = 0; size_t malloced_size = sizeof(char) * MAX_READ_SIZE; char *data, *current_offset; current_offset = NULL; *ptr = NULL; data = (char*)proxenet_xmalloc(malloced_size+1); while (true) { current_offset = data + total_bytes_read; if (ssl) { /* ssl */ ret = proxenet_ssl_read(ssl, current_offset, MAX_READ_SIZE); } else { /* plaintext */ ret = proxenet_read(sock, current_offset, MAX_READ_SIZE); } if (ret < 0) { proxenet_xfree(data); xlog(LOG_ERROR, "read(%d) = %d\n", sock, ret); return ret; } total_bytes_read += ret; if (ret == MAX_READ_SIZE) { /* may be more data to come */ malloced_size += sizeof(char) * MAX_READ_SIZE; data = (char*)proxenet_xrealloc(data, malloced_size+1); #ifdef DEBUG xlog(LOG_DEBUG, "Increasing recv buf size to %d\n", malloced_size+1); #endif continue; } break; } if (total_bytes_read == 0) { proxenet_xfree(data); return -ENODATA; } *ptr = data; return total_bytes_read; }
bool is_valid_http_request(char** request, size_t* request_len) { size_t new_request_len = -1; char *old_ptr, *new_ptr; int i = -1; int offlen = -1; old_ptr = new_ptr = NULL; old_ptr = strstr(*request, "http://"); if (old_ptr) offlen = 7; else { old_ptr = strstr(*request, "https://"); if (old_ptr) offlen = 8; } if (offlen < 0) { xlog(LOG_ERROR, "Cannot find protocol (http|https) in request:\n%s\n", *request); return false; } new_ptr = strchr(old_ptr + offlen, '/'); if (!new_ptr) { xlog(LOG_ERROR, "%s\n", "Cannot find path (must not be implicit)"); return false; } new_request_len = *request_len - (new_ptr-old_ptr); #ifdef DEBUG xlog(LOG_DEBUG, "Adjusting buffer to %d->%d bytes\n", *request_len, new_request_len); #endif for (i=0; i<new_request_len - (old_ptr-*request);i++) *(old_ptr+i) = *(new_ptr+i); *request = proxenet_xrealloc(*request, new_request_len); *request_len = new_request_len; return true; }