/* * @METHOD_NAME: end * @METHOD_DESC: It indicate that the full response for the request has been ended. No * extra calls will take place after invoke this method as it contains an implicit return * for the active callback. * * Internally, this function send the HTTP response headers, flush the enqueued body content * and release the resources used by the service. The connection could keep open depending * of the HTTP transaction. * * @METHOD_PARAM: dr the request context information hold by a duda_request_t type * @METHOD_PARAM: end_cb Defines a callback function to be invoked once the response object * finish flushing the pending data and clearing up the resources used. * @METHOD_RETURN: Upon successful completion it returns 0, otherwise it can generate an explicit * program exit due to bad API usage. */ int duda_response_end(duda_request_t *dr, void (*end_cb) (duda_request_t *)) { int ret; /* Make sure the caller set a valid HTTP response code */ if (dr->sr->headers.status == 0 && dr->_st_http_headers_off == MK_FALSE) { duda_api_exception(dr, "Callback did not set the HTTP response status"); abort(); } dr->end_callback = end_cb; ret = duda_response_send_headers(dr); if (ret == -1) { return -1; } /* flush some enqueued content */ ret = duda_queue_flush(dr); /* * The lesson of the day Feb 2, 2013: I must NEVER forget that when sending the * HTTP headers, Monkey sets the TCP_CORK flag ON in the socket in case the caller * wanted to send more data so we let know the Kernel to buffer a little more bytes. * If we do not set TCP_CORK to OFF we will face some delays in the response. * * KeepAlive was very slow due to this bug. More than 4 hours to found this silly bug. */ mk_api->socket_cork_flag(dr->cs->socket, TCP_CORK_OFF); if (ret == 0) { duda_service_end(dr); } return 0; }
/* * @METHOD_NAME: send_headers * @METHOD_DESC: Send the HTTP response headers * @METHOD_PARAM: dr the request context information hold by a duda_request_t type * @METHOD_RETURN: Upon successful completion it returns 0, on error returns -1. */ int duda_response_send_headers(duda_request_t *dr) { int r; size_t bytes = 0; struct mk_list *head; struct mk_stream *stream; if (dr->_st_http_headers_off == MK_TRUE) { dr->_st_http_headers_sent = MK_TRUE; return 0; } if (dr->_st_http_headers_sent == MK_TRUE) { return -1; } if (dr->_st_body_writes > 0) { /* FIXME: Console error */ return -1; } /* Calculate body length */ if (dr->_st_http_content_length == -2) { /* FIXME mk_list_foreach(head, &dr->channel.streams) { stream = mk_list_entry(head, struct mk_stream, _head); bytes += stream->bytes_total; } dr->request->headers.content_length = bytes; */ } else if (dr->_st_http_content_length >= 0) { dr->request->headers.content_length = dr->_st_http_content_length; } if (dr->request->headers.status <= 0) { duda_api_exception(dr, "Callback did not set the HTTP response status"); abort(); } r = mk_api->header_prepare(dr->session, dr->request); if (r != 0) { /* FIXME: Console error */ return -1; } /* Change flag status */ dr->_st_http_headers_sent = MK_TRUE; /* * Concatenate list, link temporal dr->channel nodes to parent channel * streams list. */ /* FIXME: dst-2 */ //mk_list_cat(&dr->channel.streams, &(dr->session->channel)->streams); return 0; }