void websrv_output(struct websrv_context *web, void *data, size_t length) { data_blob_append(web, &web->output.content, data, length); EVENT_FD_NOT_READABLE(web->conn->event.fde); EVENT_FD_WRITEABLE(web->conn->event.fde); web->output.output_pending = true; }
/* destroy a pending request */ static int nbt_name_request_destructor(struct nbt_name_request *req) { if (req->state == NBT_REQUEST_SEND) { DLIST_REMOVE(req->nbtsock->send_queue, req); } if (req->state == NBT_REQUEST_WAIT) { req->nbtsock->num_pending--; } if (req->name_trn_id != 0 && !req->is_reply) { idr_remove(req->nbtsock->idr, req->name_trn_id); req->name_trn_id = 0; } if (req->te) { req->te = NULL; } if (req->nbtsock->send_queue == NULL) { EVENT_FD_NOT_WRITEABLE(req->nbtsock->fde); } if (req->nbtsock->num_pending == 0 && req->nbtsock->incoming.handler == NULL) { EVENT_FD_NOT_READABLE(req->nbtsock->fde); } /* once this has been called for this req, don't call again */ talloc_set_destructor(req, NULL); return 0; }
/* called when a web connection becomes readable */ static void websrv_recv(struct stream_connection *conn, uint16_t flags) { struct web_server_data *wdata; struct websrv_context *web = talloc_get_type(conn->private_data, struct websrv_context); NTSTATUS status; uint8_t buf[1024]; size_t nread; uint8_t *p; DATA_BLOB b; /* not the most efficient http parser ever, but good enough for us */ status = socket_recv(conn->socket, buf, sizeof(buf), &nread); if (NT_STATUS_IS_ERR(status)) goto failed; if (!NT_STATUS_IS_OK(status)) return; if (!data_blob_append(web, &web->input.partial, buf, nread)) goto failed; /* parse any lines that are available */ b = web->input.partial; while (!web->input.end_of_headers && (p=(uint8_t *)memchr(b.data, '\n', b.length))) { const char *line = (const char *)b.data; *p = 0; if (p != b.data && p[-1] == '\r') { p[-1] = 0; } status = http_parse_header(web, line); if (!NT_STATUS_IS_OK(status)) return; b.length -= (p - b.data) + 1; b.data = p+1; } /* keep any remaining bytes in web->input.partial */ if (b.length == 0) { b.data = NULL; } b = data_blob_talloc(web, b.data, b.length); data_blob_free(&web->input.partial); web->input.partial = b; /* we finish when we have both the full headers (terminated by a blank line) and any post data, as indicated by the content_length */ if (web->input.end_of_headers && web->input.partial.length >= web->input.content_length) { if (web->input.partial.length > web->input.content_length) { web->input.partial.data[web->input.content_length] = 0; } EVENT_FD_NOT_READABLE(web->conn->event.fde); /* the reference/unlink code here is quite subtle. It is needed because the rendering of the web-pages, and in particular the esp/ejs backend, is semi-async. So we could well end up in the connection timeout code while inside http_process_input(), but we must not destroy the stack variables being used by that rendering process when we handle the timeout. */ if (!talloc_reference(web->task, web)) goto failed; wdata = talloc_get_type(web->task->private_data, struct web_server_data); if (wdata == NULL) goto failed; wdata->http_process_input(wdata, web); talloc_unlink(web->task, web); } return; failed: stream_terminate_connection(conn, "websrv_recv: failed"); }