/* * This function allow the core to invoke the closing connection process * when some connection was not proceesed due to a premature close or similar * exception, it also take care of invoke the STAGE_40 and STAGE_50 plugins events */ static void mk_request_premature_close(int http_status, struct mk_http_session *cs) { struct mk_http_request *sr; struct mk_list *sr_list = &cs->request_list; struct mk_list *host_list = &mk_config->hosts; /* * If the connection is too premature, we need to allocate a temporal session_request * to do not break the plugins stages */ if (mk_list_is_empty(sr_list) == 0) { sr = &cs->sr_fixed; memset(sr, 0, sizeof(struct mk_http_request)); mk_http_request_init(cs, sr); mk_list_add(&sr->_head, &cs->request_list); } else { sr = mk_list_entry_first(sr_list, struct mk_http_request, _head); } /* Raise error */ if (http_status > 0) { if (!sr->host_conf) { sr->host_conf = mk_list_entry_first(host_list, struct host, _head); } mk_http_error(http_status, cs, sr); /* STAGE_40, request has ended */ mk_plugin_stage_run_40(cs, sr); }
struct cache_req_t *cache_req_new() { struct mk_list *pool = pthread_getspecific(cache_req_pool); struct cache_req_t *req; if (mk_list_is_empty(pool) == -1) { // printf("reusing an exhisting request!\n"); req = mk_list_entry_first(pool, struct cache_req_t, _head); mk_list_del(&req->_head); if (req->buf->filled) { pipe_buf_flush(req->buf); } }
void mk_cheetah_cmd_plugins_print_stage(struct mk_list *list, const char *stage, int stage_bw) { struct plugin *p; struct mk_list *head; if (mk_list_is_empty(list) == 0) { return; } CHEETAH_WRITE("%s[%s]%s", ANSI_BOLD ANSI_YELLOW, stage, ANSI_RESET); mk_list_foreach(head, list) { p = mk_list_entry(head, struct plugin, _head); if (p->hooks & stage_bw) { CHEETAH_WRITE("\n [%s] %s v%s on \"%s\"", p->shortname, p->name, p->version, p->path); } }
/* * Copy inherit bytes from old chunk to new chunk and set as current * chunk. */ int fcgi_fd_set_chunk(struct fcgi_fd *fd, struct chunk *a, size_t inherit) { struct chunk *b = fd->chunk; size_t b_pos, a_pos; struct chunk_ptr tmp; chunk_retain(a); if (b && inherit > 0) { check(b->write >= inherit, "Not enough used on old chunk to inherit."); check(a->size - a->write > inherit, "Not enough free space on new chunk to inherit."); a_pos = a->write; b_pos = b->write - inherit; memcpy(a->data + a_pos, b->data + b_pos, inherit); a_pos += inherit; tmp.parent = a; tmp.len = a->size - a_pos; tmp.data = a->data + a_pos; check(!chunk_set_write_ptr(a, tmp), "Failed to set new write pointer."); chunk_release(b); } else if (b) { chunk_release(b); } else { check(inherit == 0, "There are no chunks to inherit from."); } fd->chunk = a; return 0; error: if (mk_list_is_empty(&a->_head)) { mk_list_del(&a->_head); } return -1; }
/* * Check if a connection can stay open using * the keepalive headers vars and Monkey configuration as criteria */ int mk_http_keepalive_check(struct client_session *cs) { struct session_request *sr_node; struct mk_list *sr_head; if (mk_list_is_empty(&cs->request_list) == 0) { return -1; } sr_head = &cs->request_list; sr_node = mk_list_entry_last(sr_head, struct session_request, _head); if (config->keep_alive == MK_FALSE || sr_node->keep_alive == MK_FALSE) { return -1; } /* Old client without Connection header */ if (sr_node->protocol < MK_HTTP_PROTOCOL_11 && sr_node->connection.len <= 0) { return -1; } /* Old client and content length to send is unknown */ if (sr_node->protocol < MK_HTTP_PROTOCOL_11 && sr_node->headers.content_length < 0) { return -1; } /* Connection was forced to close */ if (sr_node->close_now == MK_TRUE) { return -1; } /* Client has reached keep-alive connections limit */ if (cs->counter_connections >= config->max_keep_alive_request) { return -1; } return 0; }
int mk_conn_read(int socket) { int ret; int status; struct mk_http_session *cs; struct mk_http_request *sr; struct sched_list_node *sched; MK_TRACE("[FD %i] Connection Handler / read", socket); /* Plugin hook */ ret = mk_plugin_event_read(socket); switch (ret) { case MK_PLUGIN_RET_EVENT_OWNED: return MK_PLUGIN_RET_CONTINUE; case MK_PLUGIN_RET_EVENT_CLOSE: return -1; case MK_PLUGIN_RET_EVENT_CONTINUE: break; /* just return controller to invoker */ } sched = mk_sched_get_thread_conf(); cs = mk_http_session_get(socket); if (!cs) { /* Check if is this a new connection for the Scheduler */ if (!mk_sched_get_connection(sched, socket)) { MK_TRACE("[FD %i] Registering new connection"); if (mk_sched_register_client(socket, sched) == -1) { MK_TRACE("[FD %i] Close requested", socket); return -1; } /* * New connections are not registered yet into the * events loop, we need to do it manually: */ mk_event_add(sched->loop, socket, MK_EVENT_READ, NULL); return 0; } /* Create session for the client */ MK_TRACE("[FD %i] Create session", socket); cs = mk_http_session_create(socket, sched); if (!cs) { return -1; } } /* Invoke the read handler, on this case we only support HTTP (for now :) */ ret = mk_http_handler_read(socket, cs); if (ret > 0) { if (mk_list_is_empty(&cs->request_list) == 0) { /* Add the first entry */ sr = &cs->sr_fixed; mk_list_add(&sr->_head, &cs->request_list); mk_http_request_init(cs, sr); } else { sr = mk_list_entry_first(&cs->request_list, struct mk_http_request, _head); } status = mk_http_parser(sr, &cs->parser, cs->body, cs->body_length); if (status == MK_HTTP_PARSER_OK) { MK_TRACE("[FD %i] HTTP_PARSER_OK", socket); mk_http_status_completed(cs); mk_event_add(sched->loop, socket, MK_EVENT_WRITE, NULL); } else if (status == MK_HTTP_PARSER_ERROR) { mk_http_session_remove(socket); MK_TRACE("[FD %i] HTTP_PARSER_ERROR", socket); return -1; } else { MK_TRACE("[FD %i] HTTP_PARSER_PENDING", socket); } } if (ret == -EAGAIN) { return 1; } return ret; }
int mk_channel_write(struct mk_channel *channel) { ssize_t bytes = -1; struct mk_iov *iov; mk_ptr_t *ptr; struct mk_stream *stream; if (mk_list_is_empty(&channel->streams) == 0) { MK_TRACE("[CH %i] CHANNEL_EMPTY", channel->fd); return MK_CHANNEL_EMPTY; } /* Get the input source */ stream = mk_list_entry_first(&channel->streams, struct mk_stream, _head); /* * Based on the Stream type we consume on that way, not all inputs * requires to read from buffer, e.g: Static File, Pipes. */ if (channel->type == MK_CHANNEL_SOCKET) { if (stream->type == MK_STREAM_FILE) { bytes = channel_write_stream_file(channel, stream); } else if (stream->type == MK_STREAM_IOV) { MK_TRACE("[CH %i] STREAM_IOV, wrote %lu bytes", channel->fd, stream->bytes_total); iov = stream->buffer; bytes = mk_sched_conn_writev(channel, iov); if (bytes > 0) { /* Perform the adjustment on mk_iov */ mk_iov_consume(iov, bytes); } } else if (stream->type == MK_STREAM_PTR) { MK_TRACE("[CH %i] STREAM_PTR, bytes=%lu", channel->fd, stream->bytes_total); ptr = stream->buffer; bytes = mk_sched_conn_write(channel, ptr->data, ptr->len); if (bytes > 0) { /* FIXME OFFSET */ } } if (bytes > 0) { mk_stream_bytes_consumed(stream, bytes); /* notification callback, optional */ if (stream->cb_bytes_consumed) { stream->cb_bytes_consumed(stream, bytes); } if (stream->bytes_total == 0) { MK_TRACE("Stream done, unlinking"); if (stream->cb_finished) { stream->cb_finished(stream); } if (stream->preserve == MK_FALSE) { mk_stream_unlink(stream); } } if (mk_list_is_empty(&channel->streams) == 0) { MK_TRACE("[CH %i] CHANNEL_DONE", channel->fd); return MK_CHANNEL_DONE; } MK_TRACE("[CH %i] CHANNEL_FLUSH", channel->fd); return MK_CHANNEL_FLUSH; } else if (bytes <= 0) { if (stream->cb_exception) { stream->cb_exception(stream, errno); } return MK_CHANNEL_ERROR; } } return MK_CHANNEL_UNKNOWN; }