int mk_http_request_end(int socket) { int ka; struct client_session *cs; struct sched_list_node *sched; sched = mk_sched_get_thread_conf(); cs = mk_session_get(socket); if (!cs) { MK_TRACE("[FD %i] Not found", socket); return -1; } if (mk_unlikely(!sched)) { MK_TRACE("Could not find sched list node :/"); return -1; } /* * We need to ask to http_keepalive if this * connection can continue working or we must * close it. */ ka = mk_http_keepalive_check(cs); mk_request_free_list(cs); if (ka < 0) { MK_TRACE("[FD %i] No KeepAlive mode, remove", socket); mk_session_remove(socket); } else { mk_request_ka_next(cs); mk_epoll_change_mode(sched->epoll_fd, socket, MK_EPOLL_READ, MK_EPOLL_LEVEL_TRIGGERED); return 0; } return -1; }
static int mk_http_request_prepare(struct mk_http_session *cs, struct mk_http_request *sr) { int status = 0; char *temp; struct mk_list *hosts = &mk_config->hosts; struct mk_list *alias; struct mk_http_header *header; /* * Process URI, if it contains ASCII encoded strings like '%20', * it will return a new memory buffer with the decoded string, otherwise * it returns NULL */ temp = mk_utils_url_decode(sr->uri); if (temp) { sr->uri_processed.data = temp; sr->uri_processed.len = strlen(temp); } else { sr->uri_processed.data = sr->uri.data; sr->uri_processed.len = sr->uri.len; } /* Always assign the default vhost' */ sr->host_conf = mk_list_entry_first(hosts, struct host, _head); sr->user_home = MK_FALSE; /* Valid request URI? */ if (sr->uri_processed.data[0] != '/') { mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr); return MK_EXIT_OK; } /* Check if we have a Host header: Hostname ; port */ mk_http_point_header(&sr->host, &cs->parser, MK_HEADER_HOST); /* Header: Connection */ mk_http_point_header(&sr->connection, &cs->parser, MK_HEADER_CONNECTION); /* Header: Range */ mk_http_point_header(&sr->range, &cs->parser, MK_HEADER_RANGE); /* Header: If-Modified-Since */ mk_http_point_header(&sr->if_modified_since, &cs->parser, MK_HEADER_IF_MODIFIED_SINCE); /* HTTP/1.1 needs Host header */ if (!sr->host.data && sr->protocol == MK_HTTP_PROTOCOL_11) { mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr); return MK_EXIT_OK; } /* Should we close the session after this request ? */ mk_http_keepalive_check(cs, sr); /* Content Length */ header = &cs->parser.headers[MK_HEADER_CONTENT_LENGTH]; if (header->type == MK_HEADER_CONTENT_LENGTH) { sr->_content_length.data = header->val.data; sr->_content_length.len = header->val.len; } else { sr->_content_length.data = NULL; } /* Assign the first node alias */ alias = &sr->host_conf->server_names; sr->host_alias = mk_list_entry_first(alias, struct host_alias, _head); if (sr->host.data) { /* Set the given port */ if (cs->parser.header_host_port > 0) { sr->port = cs->parser.header_host_port; } /* Match the virtual host */ mk_vhost_get(sr->host, &sr->host_conf, &sr->host_alias); /* Check if this virtual host have some redirection */ if (sr->host_conf->header_redirect.data) { mk_header_set_http_status(sr, MK_REDIR_MOVED); sr->headers.location = mk_string_dup(sr->host_conf->header_redirect.data); sr->headers.content_length = 0; sr->headers.location = NULL; mk_header_prepare(cs, sr); return 0; } } /* Is requesting an user home directory ? */ if (mk_config->user_dir && sr->uri_processed.len > 2 && sr->uri_processed.data[1] == MK_USER_HOME) { if (mk_user_init(cs, sr) != 0) { mk_http_error(MK_CLIENT_NOT_FOUND, cs, sr); return MK_EXIT_ABORT; } } /* Plugins Stage 20 */ int ret; ret = mk_plugin_stage_run_20(cs, sr); if (ret == MK_PLUGIN_RET_CLOSE_CONX) { MK_TRACE("STAGE 20 requested close conexion"); return MK_EXIT_ABORT; } /* Normal HTTP process */ status = mk_http_init(cs, sr); MK_TRACE("[FD %i] HTTP Init returning %i", cs->socket, status); return status; }
/* Send response headers */ int mk_header_send(int fd, struct client_session *cs, struct session_request *sr) { int i=0; unsigned long len = 0; char *buffer = 0; mk_pointer response; struct response_headers *sh; struct mk_iov *iov; sh = &sr->headers; iov = mk_header_iov_get(); /* HTTP Status Code */ if (sh->status == MK_CUSTOM_STATUS) { response.data = sh->custom_status.data; response.len = sh->custom_status.len; } else { for (i=0; i < status_response_len; i++) { if (status_response[i].status == sh->status) { response.data = status_response[i].response; response.len = status_response[i].length; break; } } } /* Invalid status set */ mk_bug(i == status_response_len); mk_header_iov_add_entry(iov, response, mk_iov_none, MK_IOV_NOT_FREE_BUF); /* Server details */ mk_iov_add_entry(iov, sr->host_conf->header_host_signature.data, sr->host_conf->header_host_signature.len, mk_iov_crlf, MK_IOV_NOT_FREE_BUF); /* Date */ mk_iov_add_entry(iov, mk_header_short_date.data, mk_header_short_date.len, header_current_time, MK_IOV_NOT_FREE_BUF); /* Last-Modified */ if (sh->last_modified > 0) { mk_pointer *lm; lm = mk_cache_get(mk_cache_header_lm); lm->len = mk_utils_utime2gmt(&lm->data, sh->last_modified); mk_iov_add_entry(iov, mk_header_last_modified.data, mk_header_last_modified.len, *lm, MK_IOV_NOT_FREE_BUF); } /* Connection */ if (sh->connection == 0) { if (mk_http_keepalive_check(cs) == 0) { if (sr->connection.len > 0) { /* Get cached mk_pointers */ mk_pointer *ka_format = mk_cache_get(mk_cache_header_ka); mk_pointer *ka_header = mk_cache_get(mk_cache_header_ka_max); /* Compose header and add entries to iov */ mk_string_itop(config->max_keep_alive_request - cs->counter_connections, ka_header); mk_iov_add_entry(iov, ka_format->data, ka_format->len, mk_iov_none, MK_IOV_NOT_FREE_BUF); mk_iov_add_entry(iov, ka_header->data, ka_header->len, mk_header_conn_ka, MK_IOV_NOT_FREE_BUF); } } else { mk_iov_add_entry(iov, mk_header_conn_close.data, mk_header_conn_close.len, mk_iov_none, MK_IOV_NOT_FREE_BUF); } } /* Location */ if (sh->location != NULL) { mk_iov_add_entry(iov, mk_header_short_location.data, mk_header_short_location.len, mk_iov_none, MK_IOV_NOT_FREE_BUF); mk_iov_add_entry(iov, sh->location, strlen(sh->location), mk_iov_crlf, MK_IOV_FREE_BUF); } /* allowed methods */ if (sh->allow_methods.len > 0) { mk_iov_add_entry(iov, mk_header_allow.data, mk_header_allow.len, sh->allow_methods, MK_IOV_NOT_FREE_BUF) ; } /* Content type */ if (sh->content_type.len > 0) { mk_iov_add_entry(iov, mk_header_short_ct.data, mk_header_short_ct.len, sh->content_type, MK_IOV_NOT_FREE_BUF); } /* * Transfer Encoding: the transfer encoding header is just sent when * the response has some content defined by the HTTP status response */ if ((sh->status < MK_REDIR_MULTIPLE) || (sh->status > MK_REDIR_USE_PROXY)) { switch (sh->transfer_encoding) { case MK_HEADER_TE_TYPE_CHUNKED: mk_iov_add_entry(iov, mk_header_te_chunked.data, mk_header_te_chunked.len, mk_iov_none, MK_IOV_NOT_FREE_BUF); break; } } /* Content-Encoding */ if (sh->content_encoding.len > 0) { mk_iov_add_entry(iov, mk_header_content_encoding.data, mk_header_content_encoding.len, mk_iov_none, MK_IOV_NOT_FREE_BUF); mk_iov_add_entry(iov, sh->content_encoding.data, sh->content_encoding.len, mk_iov_none, MK_IOV_NOT_FREE_BUF); } /* Content-Length */ if (sh->content_length >= 0) { /* Map content length to MK_POINTER */ mk_pointer *cl; cl = mk_cache_get(mk_cache_header_cl); mk_string_itop(sh->content_length, cl); /* Set headers */ mk_iov_add_entry(iov, mk_header_content_length.data, mk_header_content_length.len, *cl, MK_IOV_NOT_FREE_BUF); } if ((sh->content_length != 0 && (sh->ranges[0] >= 0 || sh->ranges[1] >= 0)) && config->resume == MK_TRUE) { buffer = 0; /* yyy- */ if (sh->ranges[0] >= 0 && sh->ranges[1] == -1) { mk_string_build(&buffer, &len, "%s bytes %d-%ld/%ld", RH_CONTENT_RANGE, sh->ranges[0], (sh->real_length - 1), sh->real_length); mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF); } /* yyy-xxx */ if (sh->ranges[0] >= 0 && sh->ranges[1] >= 0) { mk_string_build(&buffer, &len, "%s bytes %d-%d/%ld", RH_CONTENT_RANGE, sh->ranges[0], sh->ranges[1], sh->real_length); mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF); } /* -xxx */ if (sh->ranges[0] == -1 && sh->ranges[1] > 0) { mk_string_build(&buffer, &len, "%s bytes %ld-%ld/%ld", RH_CONTENT_RANGE, (sh->real_length - sh->ranges[1]), (sh->real_length - 1), sh->real_length); mk_iov_add_entry(iov, buffer, len, mk_iov_crlf, MK_IOV_FREE_BUF); } } mk_socket_set_cork_flag(fd, TCP_CORK_ON); if (sh->cgi == SH_NOCGI || sh->breakline == MK_HEADER_BREAKLINE) { if (!sr->headers._extra_rows) { mk_iov_add_entry(iov, mk_iov_crlf.data, mk_iov_crlf.len, mk_iov_none, MK_IOV_NOT_FREE_BUF); } else { mk_iov_add_entry(sr->headers._extra_rows, mk_iov_crlf.data, mk_iov_crlf.len, mk_iov_none, MK_IOV_NOT_FREE_BUF); } } mk_socket_sendv(fd, iov); if (sr->headers._extra_rows) { mk_socket_sendv(fd, sr->headers._extra_rows); mk_iov_free(sr->headers._extra_rows); sr->headers._extra_rows = NULL; } mk_header_iov_free(iov); sh->sent = MK_TRUE; return 0; }