Beispiel #1
0
/*
 * 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);
    }
Beispiel #2
0
static struct mk_list *mk_dirhtml_create_list(DIR * dir, char *path,
                                              unsigned long *list_len)
{
    char full_path[PATH_MAX];
    struct mk_list *list;
    struct dirent *ent;
    struct mk_f_list *entry = 0;

    list = mk_api->mem_alloc(sizeof(struct mk_list));
    mk_list_init(list);

    while ((ent = readdir(dir)) != NULL) {
        if ((ent->d_name[0] == '.') && (strcmp(ent->d_name, "..") != 0))
            continue;

        /* Look just for files and dirs */
        if (ent->d_type != DT_REG && ent->d_type != DT_DIR
            && ent->d_type != DT_LNK && ent->d_type != DT_UNKNOWN) {
            continue;
        }

        snprintf(full_path, PATH_MAX, "%s%s", path, ent->d_name);
        entry = mk_dirhtml_create_element(ent->d_name,
                                          ent->d_type, full_path, list_len);
        if (!entry) {
            continue;
        }

        mk_list_add(&entry->_head, list);
    }

    return list;
}
Beispiel #3
0
void cgi_req_add(struct cgi_request *r)
{
    struct mk_list *list = pthread_getspecific(cgi_request_list);

    mk_bug(!list);
    mk_list_add(&r->_head, list);
}
Beispiel #4
0
/* Create a new mqtt request instance */
struct tcp_conn *tcp_conn_add(int fd, struct flb_in_tcp_config *ctx)
{
    int ret;
    struct tcp_conn *conn;
    struct mk_event *event;

    conn = flb_malloc(sizeof(struct tcp_conn));
    if (!conn) {
        return NULL;
    }

    /* Set data for the event-loop */
    event = &conn->event;
    MK_EVENT_NEW(event);
    event->fd           = fd;
    event->type         = FLB_ENGINE_EV_CUSTOM;
    event->handler      = tcp_conn_event;

    /* Connection info */
    conn->fd      = fd;
    conn->ctx     = ctx;
    conn->buf_len = 0;
    conn->rest    = 0;
    conn->status  = TCP_NEW;

    conn->buf_data = flb_malloc(ctx->chunk_size);
    if (!conn->buf_data) {
        perror("malloc");
        close(fd);
        flb_error("[in_tcp] could not allocate new connection");
        flb_free(conn);
        return NULL;
    }
    conn->buf_size = ctx->chunk_size;
    conn->in       = ctx->in;

    /* Initialize JSON parser */
    flb_pack_state_init(&conn->pack_state);

    /* Register instance into the event loop */
    ret = mk_event_add(ctx->evl, fd, FLB_ENGINE_EV_CUSTOM, MK_EVENT_READ, conn);
    if (ret == -1) {
        flb_error("[in_tcp] could not register new connection");
        close(fd);
        flb_free(conn->buf_data);
        flb_free(conn);
        return NULL;
    }

    mk_list_add(&conn->_head, &ctx->connections);

    return conn;
}
Beispiel #5
0
/*
 * Move a http thread context from sched->thread to sched->threads_purge list.
 * On this way the scheduler will release or reasign the resource later.
 */
int mk_http_thread_purge(struct mk_http_thread *mth, int close)
{
    struct mk_sched_worker *sched;

    sched = mk_sched_get_thread_conf();
    if (!sched) {
        return -1;
    }

    mth->close = close;
    mk_list_del(&mth->_head);
    mk_list_add(&mth->_head, &sched->threads_purge);

    return 0;
}
Beispiel #6
0
struct mk_http_thread *mk_http_thread_create(int type,
                                             struct mk_vhost_handler *handler,
                                             struct mk_http_session *session,
                                             struct mk_http_request *request,
                                             int n_params,
                                             struct mk_list *params)
{
    size_t stack_size;
    struct mk_thread *th = NULL;
    struct mk_http_thread *mth;
    struct mk_sched_worker *sched;

    sched = mk_sched_get_thread_conf();
    if (!sched) {
        return NULL;
    }

    th = mk_thread_new(sizeof(struct mk_http_thread), NULL);
    if (!th) {
        return NULL;
    }

    mth = (struct mk_http_thread *) MK_THREAD_DATA(th);
    if (!mth) {
        return NULL;
    }

    mth->session = session;
    mth->request = request;
    mth->parent  = th;
    mth->close   = MK_FALSE;
    request->thread = mth;
    mk_list_add(&mth->_head, &sched->threads);

    th->caller = co_active();
    th->callee = co_create(MK_THREAD_STACK_SIZE,
                           thread_cb_init_vars, &stack_size);

#ifdef MK_HAVE_VALGRIND
    th->valgrind_stack_id = VALGRIND_STACK_REGISTER(th->callee,
                                                    ((char *)th->callee) + stack_size);
#endif

    /* Workaround for makecontext() */
    thread_params_set(th, type, handler, session, request, n_params, params);

    return mth;
}
/*
 * @METHOD_NAME: chan_send
 * @METHOD_DESC: add a new element to the given channel.
 * @METHOD_PROTO: int chan_send(mk_thread_channel_t *chan, void *data)
 * @METHOD_PARAM: chan the target channel to send.
 * @METHOD_PARAM: data the new element to be sent to channel.
 * @METHOD_RETURN: return THREAD_CHANNEL_BROKEN if the other side of the pipe
 * is closed, otherwise return THREAD_CHANNEL_OK.
 */
int mk_thread_channel_send(struct mk_thread_channel *chan, void *data)
{
    struct mk_thread_channel_elem *elem;

    assert(chan);
    if (chan->receiver == -1) {
        return MK_THREAD_CHANNEL_BROKEN;
    }
    if (chan->used == chan->size) {
        // channel is full
        mk_thread_resume(chan->receiver);
    }

    elem = mk_thread_channel_elem_create(data);
    mk_list_add(&elem->_head, &chan->bufs);
    chan->used++;
    return MK_THREAD_CHANNEL_OK;
}
Beispiel #8
0
/* Creates a web service instance */
struct duda_service *duda_service_create(struct duda *d, char *root, char *log,
                                         char *data, char *html, char *service)
{
    int ret;
    void *handle;
    struct duda_service *ds;
    struct duda_api_objects *api;

    if (!d) {
        return NULL;
    }

    /* Check access to root, log, data and html directories */
    if (root) {
        ret = validate_dir(root);
        if (ret != 0) {
            return NULL;
        }
    }
    if (log) {
        ret = validate_dir(log);
        if (ret != 0) {
            return NULL;
        }
    }
    if (data) {
        ret = validate_dir(log);
        if (ret != 0) {
            return NULL;
        }
    }
    if (html) {
        ret = validate_dir(html);
        if (ret != 0) {
            return NULL;
        }
    }

    /* Validate the web service file */
    handle = dlopen(service, RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "Error opening web service file '%s'\n", service);
        return NULL;
    }

    /* Create web service context */
    ds = mk_mem_alloc_z(sizeof(struct duda_service));
    if (!ds) {
        dlclose(handle);
        return NULL;
    }

    /* Root prefix path */
    if (root) {
        ds->path_root = mk_string_dup(root);
    }

    /*
     * If root prefix path is set, for all incoming paths that are not
     * absolute, we prefix the path
     */
    if (log) {
        ds->path_log  = service_path(root, log);
    }
    if (data) {
        ds->path_data = service_path(root, data);
    }
    if (html) {
        ds->path_html = service_path(root, html);
    }
    if (service) {
        ds->path_service = service_path(root, service);
    }
    ds->dl_handle = handle;
    mk_list_add(&ds->_head, &d->services);

    /* Initialize references for API objects */
    mk_list_init(&ds->router_list);

    api = duda_api_create();
    map_internals(ds, api);

    return ds;
}
Beispiel #9
0
/* Add a parameter to a method */
void duda_method_add_param(duda_param_t *param, duda_method_t *method)
{
    mk_list_add(&param->_head, &method->params);
}
Beispiel #10
0
/* Add a method to an interface */
void duda_interface_add_method(duda_method_t *method,
                               duda_interface_t *iface)
{
    mk_list_add(&method->_head, &iface->methods);
}
Beispiel #11
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;
}
Beispiel #12
0
static int mk_request_parse(struct client_session *cs)
{
    int i, end;
    int blocks = 0;
    struct session_request *sr_node;
    struct mk_list *sr_list, *sr_head;

    for (i = 0; i <= cs->body_pos_end; i++) {
        /*
         * Pipelining can just exists in a persistent connection or
         * well known as KeepAlive, so if we are in keepalive mode
         * we should check if we have multiple request in our body buffer
         */
        end = mk_string_search(cs->body + i, mk_endblock.data, MK_STR_SENSITIVE) + i;
        if (end <  0) {
            return -1;
        }

        /* Allocating request block */
        if (blocks == 0) {
            sr_node = &cs->sr_fixed;
            memset(sr_node, '\0', sizeof(struct session_request));
        }
        else {
            sr_node = mk_mem_malloc_z(sizeof(struct session_request));
        }
        mk_request_init(sr_node);

        /* We point the block with a mk_ptr_t */
        sr_node->body.data = cs->body + i;
        sr_node->body.len = end - i;

        /* Method, previous catch in mk_http_pending_request */
        if (i == 0) {
            sr_node->method = cs->first_method;
        }
        else {
            sr_node->method = mk_http_method_get(sr_node->body.data);
        }

        /* Looking for POST data */
        if (sr_node->method == MK_HTTP_METHOD_POST) {
            int offset;
            offset = end + mk_endblock.len;
            sr_node->data = mk_method_get_data(cs->body + offset,
                                               cs->body_length - offset);
        }

        /* Increase index to the end of the current block */
        i = (end + mk_endblock.len) - 1;

        /* Link block */
        mk_list_add(&sr_node->_head, &cs->request_list);

        /* Update counter */
        blocks++;
    }

    /* DEBUG BLOCKS
    struct mk_list *head;
    struct session_request *entry;

    printf("\n*******************\n");
    mk_list_foreach(head, &cs->request_list) {
        entry = mk_list_entry(head, struct session_request, _head);
        mk_ptr_print(entry->body);
        fflush(stdout);
    }
    */

    /* Checking pipelining connection */
    if (blocks > 1) {
        sr_list = &cs->request_list;
        mk_list_foreach(sr_head, sr_list) {
            sr_node = mk_list_entry(sr_head, struct session_request, _head);
            /* Pipelining request must use GET or HEAD methods */
            if (sr_node->method != MK_HTTP_METHOD_GET &&
                sr_node->method != MK_HTTP_METHOD_HEAD) {
                return -1;
            }
        }
Beispiel #13
0
static inline int header_lookup(struct mk_http_parser *p, char *buffer)
{
    int i;
    int len;
    int pos;
    long val;
    char *endptr;
    char *tmp;

    struct mk_http_header *header;
    struct mk_http_header *header_extra;
    struct row_entry *h;

    len = (p->header_sep - p->header_key);

    for (i = p->header_min; i <= p->header_max; i++) {
        h = &mk_headers_table[i];

        /* Check string length first */
        if (h->len != len) {
            continue;
        }

        if (header_cmp(h->name + 1, buffer + p->header_key + 1, len - 1) == 0) {
            /* We got a header match, register the header index */
            header = &p->headers[i];
            header->type = i;
            header->key.data = buffer + p->header_key;
            header->key.len  = len;
            header->val.data = buffer + p->header_val;
            header->val.len  = p->end - p->header_val;
            p->header_count++;
            mk_list_add(&header->_head, &p->header_list);

            if (i == MK_HEADER_HOST) {
                /* Handle a possible port number in the Host header */
                int sep = str_searchr(header->val.data, ':', header->val.len);
                if (sep > 0) {
                    int plen;
                    short int port_size = 6;
                    char port[port_size];

                    plen = header->val.len - sep - 1;
                    if (plen <= 0 || plen >= port_size) {
                        return -MK_CLIENT_BAD_REQUEST;
                    }
                    memcpy(&port, header->val.data + sep + 1, plen);
                    port[plen] = '\0';

                    errno = 0;
                    val = strtol(port, &endptr, 10);
                    if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
                        || (errno != 0 && val == 0)) {
                        return -MK_CLIENT_BAD_REQUEST;
                    }

                    if (endptr == port || *endptr != '\0') {
                        return -MK_CLIENT_BAD_REQUEST;
                    }

                    p->header_host_port = val;

                    /* Re-set the Host header value without port */
                    header->val.len = sep;
                }
            }
            else if (i == MK_HEADER_CONTENT_LENGTH) {
                errno = 0;
                val = strtol(header->val.data, &endptr, 10);
                if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
                    || (errno != 0 && val == 0)) {
                    return -MK_CLIENT_REQUEST_ENTITY_TOO_LARGE;
                }
                if (endptr == header->val.data) {
                    return -1;
                }
                if (val < 0) {
                    return -1;
                }

                p->header_content_length = val;
            }
            else if (i == MK_HEADER_CONNECTION) {
                /* Check Connection: Keep-Alive */
                if (header->val.len == sizeof(MK_CONN_KEEP_ALIVE) - 1) {
                    if (header_cmp(MK_CONN_KEEP_ALIVE,
                                   header->val.data,
                                   header->val.len ) == 0) {
                        p->header_connection = MK_HTTP_PARSER_CONN_KA;
                    }
                }
                /* Check Connection: Close */
                else if (header->val.len == sizeof(MK_CONN_CLOSE) -1) {
                    if (header_cmp(MK_CONN_CLOSE,
                                   header->val.data, header->val.len) == 0) {
                        p->header_connection = MK_HTTP_PARSER_CONN_CLOSE;
                    }
                }
                else {
                    p->header_connection = MK_HTTP_PARSER_CONN_UNKNOWN;

                    /* Try to find some known values */

                    /* Connection: upgrade */
                    pos = mk_string_search_n(header->val.data,
                                             "Upgrade",
                                             MK_STR_INSENSITIVE,
                                             header->val.len);
                    if (pos >= 0) {
                        p->header_connection = MK_HTTP_PARSER_CONN_UPGRADE;
                    }

                    /* Connection: HTTP2-Settings */
                    pos = mk_string_search_n(header->val.data,
                                             "HTTP2-Settings",
                                             MK_STR_INSENSITIVE,
                                             header->val.len);
                    if (pos >= 0) {
                        p->header_connection |= MK_HTTP_PARSER_CONN_HTTP2_SE;
                    }
                }
            }
            else if (i == MK_HEADER_UPGRADE) {
                    if (header_cmp(MK_UPGRADE_H2C,
                                   header->val.data, header->val.len) == 0) {
                        p->header_upgrade = MK_HTTP_PARSER_UPGRADE_H2C;
                    }
            }

            return 0;
        }
    }

    /*
     * The header_lookup did not match any known header, so we register this
     * entry into the headers_extra array.
     */
    if (p->headers_extra_count < MK_HEADER_EXTRA_SIZE) {
        header_extra = &p->headers_extra[p->headers_extra_count];
        header_extra->key.data = tmp = (buffer + p->header_key);
        header_extra->key.len  = len;

        /* Transform the header key string to lowercase */
        for (i = 0; i < len; i++) {
            tmp[i] = tolower(tmp[i]);
        }

        header_extra->val.data = buffer + p->header_val;
        header_extra->val.len  = p->end - p->header_val;
        p->headers_extra_count++;
        p->header_count++;
        mk_list_add(&header_extra->_head, &p->header_list);
        return 0;
    }

    /*
     * Header is unknown and we cannot store it on our extra headers
     * list as it's already full. Request is too large.
     */
    return -MK_CLIENT_REQUEST_ENTITY_TOO_LARGE;
}
Beispiel #14
0
/* Read configuration parameters */
int mk_patas_conf(char *confdir)
{
    int res;
    int val_port;
    char *val_host;
    char *val_uri;
    unsigned long len;
    char *conf_path=NULL;

    struct mk_config_section *section;
    struct mk_config_entry *entry;
    struct mk_patas_node *node;

    /* Init nodes list */
    mk_patas_nodes_list = mk_api->mem_alloc(sizeof(struct mk_list));
    mk_list_init(mk_patas_nodes_list);

    /* Read configuration */
    mk_api->str_build(&conf_path, &len, "%s/patas.conf", confdir);
    conf = mk_api->config_create(conf_path);
    section = mk_api->config_section_get(conf, "NODE");

    while (section) { 
        entry = section->entry;
        val_host = NULL;
        val_port = -1;
        val_uri = NULL;

        /* Get section values */
        val_host = mk_api->config_section_getval(section, "IP", MK_CONFIG_VAL_STR);
        val_port = (int)  mk_api->config_section_getval(section, "Port", MK_CONFIG_VAL_NUM);
        val_uri  = mk_api->config_section_getval(section, "Uri", MK_CONFIG_VAL_LIST);

        if (val_host && val_uri && val_port > 0) {
            /* validate that node:ip is not pointing this server */
            if (mk_patas_validate_node(val_host, val_port) < 0) {
                break;
            }

            /* alloc node */
            node = mk_api->mem_alloc(sizeof(struct mk_patas_node));
            node->host = val_host;
            node->port = val_port;
                
            /* pre-socket stuff */
            node->sockaddr = mk_api->mem_alloc_z(sizeof(struct sockaddr_in));
            node->sockaddr->sin_family = AF_INET;

            res = inet_pton(AF_INET, node->host, 
                            (void *) (&(node->sockaddr->sin_addr.s_addr)));
            if (res < 0) {
                mk_warn("Can't set remote->sin_addr.s_addr");
                mk_api->mem_free(node->sockaddr);
                return -1;
            }
            else if (res == 0) {
                mk_err("Invalid IP address");
                mk_api->mem_free(node->sockaddr);
                return -1;
            }

            node->sockaddr->sin_port = htons(node->port);
                
            /* add node to list */
            PLUGIN_TRACE("Balance Node: %s:%i", val_host, val_port);

            mk_list_add(&node->_head, mk_patas_nodes_list);
            mk_patas_n_nodes++;
        }
        section = section->next;
    }

    mk_api->mem_free(conf_path);
    return 0;
}
Beispiel #15
0
int duda_queue_add(struct duda_queue_item *item, struct mk_list *queue)
{
    mk_list_add(&item->_head, queue);
    return 0;
}