void Connection_fingerprint_from_cert(Connection *conn) { x509_cert* _x509P = conn->iob->ssl.peer_cert; int i = 0; debug("Connection_send_to_handler: peer_cert: %016lX: tag=%d length=%ld", (unsigned long) _x509P, _x509P ? _x509P->raw.tag : -1, _x509P ? _x509P->raw.len : -1); if (_x509P != NULL && _x509P->raw.len > 0) { sha1_context ctx; unsigned char sha1sum[CERT_FINGERPRINT_SIZE + 1] = {0}; sha1_starts(&ctx); sha1_update(&ctx, _x509P->raw.p, _x509P->raw.len); sha1_finish(&ctx, sha1sum); bstring hex = bfromcstr(""); for (i = 0; i < (int)sizeof(sha1sum); i++) { bformata(hex, "%02X", sha1sum[i]); } Request_set(conn->req, &PEER_CERT_SHA1_KEY, hex, 1); } }
int Upload_notify(Connection *conn, Handler *handler, const char *stage, bstring tmp_name) { bstring key = bformat("x-mongrel2-upload-%s", stage); Request_set(conn->req, key, bstrcpy(tmp_name), 1); return Connection_send_to_handler(conn, handler, "", 0, NULL); }
static void header_field_cb(void *data, const char *field, size_t flen, const char *value, size_t vlen) { Request *req = (Request *)data; if(hash_isfull(req->headers)) { log_err("Request had more than %d headers allowed by limits.header_count.", MAX_HEADER_COUNT); } else { bstring vstr = blk2bstr(value, vlen); bstring fstr = blk2bstr(field, flen); btolower(fstr); Request_set(req, fstr, vstr, 0); bdestroy(fstr); // we still own the key } }
int Connection_read_header(Connection *conn, Request *req) { char *data = IOBuf_start(conn->iob); int avail = IOBuf_avail(conn->iob); int rc = 0; size_t nparsed = 0; int tries = 0; Request_start(req); for(tries = 0; rc == 0 && tries < CLIENT_READ_RETRIES; tries++) { if(avail > 0) { rc = Request_parse(req, data, avail, &nparsed); } if(rc == 0) { data = IOBuf_read_some(conn->iob, &avail); check_debug(!IOBuf_closed(conn->iob), "Client closed during read."); } } error_unless(tries < CLIENT_READ_RETRIES, conn, 400, "Too many small packet read attempts."); error_unless(rc == 1, conn, 400, "Error parsing request."); // add the x-forwarded-for header Request_set(conn->req, bstrcpy(&HTTP_X_FORWARDED_FOR), blk2bstr(conn->remote, IPADDR_SIZE), 1); check_should_close(conn, conn->req); return nparsed; error: return -1; }
int Connection_read_wspacket(Connection *conn) { bstring payload=NULL; uint8_t *dataU=NULL; char *data = IOBuf_start(conn->iob); int avail = IOBuf_avail(conn->iob); int64_t packet_length=-1; int smaller_packet_length; int header_length; char key[4]; int i; int data_length; int tries = 0; int rc=0; int fin; int inprogFlags=0; int isControl; int flags; again: dataU=NULL; data = IOBuf_start(conn->iob); avail = IOBuf_avail(conn->iob); packet_length=-1; smaller_packet_length=0; header_length=0; i=0; data_length=0; tries = 0; rc=0; fin=0; for(tries = 0; packet_length == -1 && tries < 8*CLIENT_READ_RETRIES; tries++) { if(avail > 0) { packet_length = Websocket_packet_length((uint8_t *)data, avail); } if(packet_length == -1) { data = IOBuf_read_some(conn->iob, &avail); check_debug(!IOBuf_closed(conn->iob), "Client closed during read."); } } check(packet_length > 0,"Error receiving websocket packet header.") check_debug(packet_length <= INT_MAX,"Websocket packet longer than MAXINT."); /* TODO properly terminate WS connection */ smaller_packet_length = (int)packet_length; /* TODO check for maximum length */ header_length=Websocket_header_length((uint8_t *) data, avail); data_length=smaller_packet_length-header_length; dataU = (uint8_t *)IOBuf_read_all(conn->iob,header_length,8*CLIENT_READ_RETRIES); memcpy(key,dataU+header_length-4,4); flags=dataU[0]; if (payload==NULL) { inprogFlags=flags; } fin=(WS_fin(dataU)); isControl=(WS_is_control(dataU)); { const char *error=WS_validate_packet(dataU,payload!=NULL); check(error==NULL,"%s",error); } dataU = (uint8_t *)IOBuf_read_all(conn->iob,data_length, 8*CLIENT_READ_RETRIES); check(dataU != NULL, "Client closed the connection during websocket packet."); for(i=0;i<data_length;++i) { dataU[i]^=key[i%4]; } if(isControl) /* Control frames get sent right-away */ { Request_set(conn->req,bfromcstr("FLAGS"),bformat("0x%X",flags|0x80),1); rc = Connection_send_to_handler(conn, conn->handler, (void *)dataU,data_length); check_debug(rc == 0, "Failed to deliver to the handler."); } else { if(fin) { Request_set(conn->req,bfromcstr("FLAGS"),bformat("0x%X",inprogFlags|0x80),1); } if (payload == NULL) { if (fin) { rc = Connection_send_to_handler(conn, conn->handler, (void *)dataU,data_length); check_debug(rc == 0, "Failed to deliver to the handler."); } else { payload = blk2bstr(dataU,data_length); check(payload != NULL,"Allocation failed"); } } else { check(BSTR_OK == bcatblk(payload,dataU,data_length), "Concatenation failed"); if (fin) { rc = Connection_send_to_handler(conn, conn->handler, bdata(payload),blength(payload)); check_debug(rc == 0, "Failed to deliver to the handler."); bdestroy(payload); payload=NULL; } } } if (payload != NULL) { goto again; } return packet_length; error: bdestroy(payload); return -1; }
int Upload_stream(Connection *conn, Handler *handler, int content_len) { char *data = NULL; int avail = 0; int offset = 0; int first_chunk = 1; int rc; hash_t *altheaders = NULL; bstring offsetstr; debug("max content length: %d, content_len: %d", MAX_CONTENT_LENGTH, content_len); IOBuf_resize(conn->iob, MAX_CONTENT_LENGTH); // give us a good buffer size while(content_len > 0) { if(first_chunk) { // read whatever's there data = IOBuf_read_some(conn->iob, &avail); } else if(conn->sendCredits > 0) { // read up to credits data = IOBuf_read(conn->iob, conn->sendCredits < content_len ? conn->sendCredits : content_len, &avail); conn->sendCredits -= avail; } else { // sleep until we have credits tasksleep(&conn->uploadRendez); continue; } check(!IOBuf_closed(conn->iob), "Closed while reading from IOBuf."); content_len -= avail; offsetstr = bformat("%d", offset); if(first_chunk) { Request_set(conn->req, &UPLOAD_STREAM, offsetstr, 1); if(content_len == 0) { Request_set(conn->req, &UPLOAD_STREAM_DONE, bfromcstr("1"), 1); } } else { altheaders = hash_create(2, (hash_comp_t)bstrcmp, bstr_hash_fun); add_to_hash(altheaders, &UPLOAD_STREAM, offsetstr); if(content_len == 0) { add_to_hash(altheaders, &UPLOAD_STREAM_DONE, bfromcstr("1")); } } rc = Connection_send_to_handler(conn, handler, data, avail, altheaders); check_debug(rc == 0, "Failed to deliver to the handler."); if(altheaders != NULL) { hash_free_nodes(altheaders); hash_destroy(altheaders); altheaders = NULL; } check(IOBuf_read_commit(conn->iob, avail) != -1, "Commit failed while streaming."); first_chunk = 0; offset += avail; } check(content_len == 0, "Failed to write everything to the large upload tmpfile."); return 0; error: return -1; }