Example #1
0
void
Lookup_Test::test_char_lookup_1 ()
{
  const char *str = 0;
  char ch = 0;

  ch = char_lookup (&str, "bac", 3);
  CPPUNIT_ASSERT (ch == 0);

  str = (char *) "";
  ch = char_lookup (&str, "bac", 3);
  CPPUNIT_ASSERT (ch == 0);

  str = (char *)  "abc";
  ch = char_lookup (&str, "bca", 3);
  CPPUNIT_ASSERT (ch == 'a');

  const char *strv[] = {
    (char *) "abc",
    (char *) "bca",
    (char *) "cab",
    (char *) " abc",
    (char *) "bca",
    (char *) "  cab"
  };

  const char cv[] = {'a', 'b', 'c'};

  for (uint idx = 0; idx < 3; idx++)
    {
      ch = char_lookup (&strv[idx], "bca", 3);
      ASSERT_IDX (ch == *strv[idx]);
    }

  for (uint idx = 3; idx < 6; idx++)
    {
      ch = char_lookup (&strv[idx], "bca", 3, true);

      ASSERT_IDX (ch == cv[idx - 3]);
    }
}
Example #2
0
/*
 * Parse the protocol and point relevant fields, don't take logic decisions
 * based on this, just parse to locate things.
 */
int mk_http_parser(struct mk_http_request *req, struct mk_http_parser *p,
                   char *buffer, int buf_len, struct mk_server *server)
{
    int s;
    int tmp;
    int ret;
    int len;

    /* lazy test

    printf("p->i=%i buf_len=%i\n",
           p->i, buf_len);

    for (s = p->i; s < buf_len; s++) {
        if (buffer[s] == '\r') {
            printf("CR");
        }
        else if (buffer[s] == '\n') {
            printf("LF");
        }
        else {
            printf("%c", buffer[s]);
        }
    }
    printf("\n");
    */

    len = buf_len;
    for (; p->i < len; p->i++, p->chars++) {
        /* FIRST LINE LEVEL: Method, URI & Protocol */
        if (p->level == REQ_LEVEL_FIRST) {
            switch (p->status) {
            case MK_ST_REQ_METHOD:                      /* HTTP Method */
                if (p->chars == -1) {
                    switch (buffer[p->i]) {
                    case 'G':
                        p->method = MK_METHOD_GET;
                        break;
                    case 'P':
                        p->method = MK_METHOD_POST;
                        break;
                    case 'H':
                        p->method = MK_METHOD_HEAD;
                        break;
                    case 'D':
                        p->method = MK_METHOD_DELETE;
                        break;
                    case 'O':
                        p->method = MK_METHOD_OPTIONS;
                        break;
                    }
                    continue;
                }

                if (buffer[p->i] == ' ') {
                    mark_end();
                    p->status = MK_ST_REQ_URI;
                    if (p->end < 2) {
                        return MK_HTTP_PARSER_ERROR;
                    }
                    method_lookup(req, p, buffer);
                    start_next();
                }
                else {
                    if ((p->i - p->start) > 10) {
                        return MK_HTTP_PARSER_ERROR;
                    }
                }
                break;
            case MK_ST_REQ_URI:                         /* URI */
                if (buffer[p->i] == ' ') {
                    mark_end();
                    p->status = MK_ST_REQ_PROT_VERSION;
                    if (field_len() < 1) {
                        return MK_HTTP_PARSER_ERROR;
                    }
                    request_set(&req->uri, p, buffer);
                    start_next();
                }
                else if (buffer[p->i] == '?') {
                    mark_end();
                    request_set(&req->uri, p, buffer);
                    p->status = MK_ST_REQ_QUERY_STRING;
                    start_next();
                }
                else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') {
                    mk_http_error(MK_CLIENT_BAD_REQUEST, req->session,
                                  req, server);
                    return MK_HTTP_PARSER_ERROR;
                }
                break;
            case MK_ST_REQ_QUERY_STRING:                /* Query string */
                char_lookup(buffer, ' ', len, p);
                if (buffer[p->i] == ' ') {
                    mark_end();
                    request_set(&req->query_string, p, buffer);
                    p->status = MK_ST_REQ_PROT_VERSION;
                    start_next();
                }
                else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') {
                    mk_http_error(MK_CLIENT_BAD_REQUEST, req->session,
                                  req, server);
                    return MK_HTTP_PARSER_ERROR;
                }
                break;
            case MK_ST_REQ_PROT_VERSION:                /* Protocol Version */
                /*
                 * Most of the time we already have the string version in our
                 * buffer, for that case try to match the version and avoid
                 * loop rounds.
                 */
                if (p->start + 6 >= p->i) {
                    continue;
                }

                tmp = p->start;
                if (buffer[tmp] == 'H' &&
                    buffer[tmp + 1] == 'T' &&
                    buffer[tmp + 2] == 'T' &&
                    buffer[tmp + 3] == 'P' &&
                    buffer[tmp + 4] == '/' &&
                    buffer[tmp + 5] == '1' &&
                    buffer[tmp + 6] == '.') {

                    request_set(&req->protocol_p, p, buffer);
                    req->protocol_p.len = 8;
                    mk_http_set_minor_version(buffer[tmp + 7]);
                }
                else {
                    mk_http_error(MK_SERVER_HTTP_VERSION_UNSUP,
                                  req->session, req, server);
                    return MK_HTTP_PARSER_ERROR;
                }
                p->status = MK_ST_FIRST_CONTINUE;
                break;
            case MK_ST_FIRST_CONTINUE:
                if (buffer[p->i] == '\r') {
                    p->status = MK_ST_FIRST_FINALIZING;
                }
                else {
                    return MK_HTTP_PARSER_ERROR;
                }
                break;
            case MK_ST_FIRST_FINALIZING:                  /* New Line */
                if (buffer[p->i] == '\n') {
                    p->level = REQ_LEVEL_CONTINUE;
                    start_next();
                }
                else {
                    return MK_HTTP_PARSER_ERROR;
                }
                break;
            case MK_ST_BLOCK_END:
                if (buffer[p->i] == '\n') {
                    return mk_http_parser_ok(req, p, server);
                }
                else {
                    return MK_HTTP_PARSER_ERROR;
                }
                break;
            };
        }
        else if (p->level == REQ_LEVEL_CONTINUE) {
            if (buffer[p->i] == '\r') {
                p->level  = REQ_LEVEL_FIRST;
                p->status = MK_ST_BLOCK_END;
            }
            else {
                p->level  = REQ_LEVEL_HEADERS;
                p->status = MK_ST_HEADER_KEY;
                p->chars  = 0;
            }
        }
        /* HEADERS: all headers stuff */
        if (p->level == REQ_LEVEL_HEADERS) {
            /* Expect a Header key */
            if (p->status == MK_ST_HEADER_KEY) {
                if (buffer[p->i] == '\r') {
                    if (p->chars == 0) {
                        p->level = REQ_LEVEL_END;
                        start_next();
                    }
                    else {
                        return MK_HTTP_PARSER_ERROR;
                    }
                }

                if (p->chars == 0) {
                    /*
                     * We reach the start of a Header row, lets catch the most
                     * probable header.
                     *
                     * The goal of this 'first row character lookup', is to define a
                     * small range set of probable headers comparison once we catch
                     * a header end.
                     */
                    s = tolower(buffer[p->i]);
                    switch (s) {
                    case 'a':
                        p->header_min = MK_HEADER_ACCEPT;
                        p->header_max = MK_HEADER_AUTHORIZATION;
                        break;
                    case 'c':
                        p->header_min = MK_HEADER_CACHE_CONTROL;
                        p->header_max = MK_HEADER_CONTENT_TYPE;
                        break;
                    case 'h':
                        p->header_min = MK_HEADER_HOST;
                        p->header_max = MK_HEADER_HTTP2_SETTINGS;
                        break;
                    case 'i':
                        header_scope_eq(p, MK_HEADER_IF_MODIFIED_SINCE);
                        break;
                    case 'l':
                        p->header_min = MK_HEADER_LAST_MODIFIED;
                        p->header_max = MK_HEADER_LAST_MODIFIED_SINCE;
                        break;
                    case 'r':
                        p->header_min = MK_HEADER_RANGE;
                        p->header_max = MK_HEADER_REFERER;
                        break;
                    case 'u':
                        p->header_min = MK_HEADER_UPGRADE;
                        p->header_max = MK_HEADER_USER_AGENT;
                        break;
                    default:
                        p->header_key = -1;
                        p->header_sep = -1;
                        p->header_min = -1;
                        p->header_max = -1;
                    };
                    p->header_key = p->i;
                    continue;
                }

                /* Found key/value separator */
                char_lookup(buffer, ':', len, p);
                if (buffer[p->i] == ':') {
                    /* Set the key/value middle point */
                    p->header_sep = p->i;

                    /* validate length */
                    mark_end();
                    if (field_len() < 1) {
                        return MK_HTTP_PARSER_ERROR;
                    }

                    /* Wait for a value */
                    p->status = MK_ST_HEADER_VALUE;
                    start_next();
                }
            }
            /* Parsing the header value */
            else if (p->status == MK_ST_HEADER_VALUE) {
                /* Trim left, set starts only when found something != ' ' */
                if (buffer[p->i] == '\r' || buffer[p->i] == '\n') {
                    return MK_HTTP_PARSER_ERROR;
                }
                else if (buffer[p->i] != ' ') {
                    p->status = MK_ST_HEADER_VAL_STARTS;
                    p->start = p->header_val = p->i;
                }
                continue;
            }
            /* New header row starts */
            else if (p->status == MK_ST_HEADER_VAL_STARTS) {
                /* Maybe there is no more headers and we reach the end ? */
                if (buffer[p->i] == '\r') {
                    mark_end();
                    if (field_len() <= 0) {
                        return MK_HTTP_PARSER_ERROR;
                    }

                    /*
                     * A header row has ended, lets lookup the header and populate
                     * our headers table index.
                     */
                    ret = header_lookup(p, buffer);
                    if (ret != 0) {
                        if (ret < -1) {
                            mk_http_error(-ret, req->session, req, server);
                        }
                        return MK_HTTP_PARSER_ERROR;
                    }

                    /* Try to catch next LF */
                    if (p->i + 1 < len) {
                        if (buffer[p->i + 1] == '\n') {
                            p->i++;
                            p->status = MK_ST_HEADER_KEY;
                            p->chars = -1;
                            start_next();
                        }
                    }

                    p->status = MK_ST_HEADER_END;
                    start_next();
                }
                else if (buffer[p->i] == '\n' && buffer[p->i - 1] != '\r') {
                    return MK_HTTP_PARSER_ERROR;
                }
            }
            else if (p->status == MK_ST_HEADER_END) {
                if (buffer[p->i] == '\n') {
                    p->status = MK_ST_HEADER_KEY;
                    p->chars = -1;
                    start_next();
                }
                else {
                    return MK_HTTP_PARSER_ERROR;
                }
            }
        }
        else if (p->level == REQ_LEVEL_END) {
            if (buffer[p->i] == '\n') {
                if (p->header_content_length > 0) {
                    p->level = REQ_LEVEL_BODY;
                    p->chars = -1;
                    start_next();
                }
                else {
                    return mk_http_parser_ok(req, p, server);
                }
            }
            else {
                return MK_HTTP_PARSER_ERROR;
            }
        }
        else if (p->level == REQ_LEVEL_BODY) {
            /*
             * Reaching this level can means two things:
             *
             * - A Pipeline Request
             * - A Body content (POST/PUT methods)
             */
            if (p->header_content_length > 0) {

                p->body_received = len - p->start;
                if ((len - p->start) < p->header_content_length) {
                    return MK_HTTP_PARSER_PENDING;
                }

                /* Cut off */
                p->i += p->body_received;
                req->data.len  = p->body_received;
                req->data.data = (buffer + p->start);
            }
            return mk_http_parser_ok(req, p, server);
        }
    }

    return MK_HTTP_PARSER_PENDING;
}