Exemplo n.º 1
0
int sdper_parse(struct sdper const *sdper, size_t *head_sz, uint8_t const *packet, size_t packet_len, void *user_data)
{
    // REVIEW: eols and spcs should be provided by liner.
    struct liner_delimiter
        eols[] = { { "\r\n", 2 }, { "\n", 1 } },
        cols[] = { { "= ", 2}, { "=", 1 } };
    struct liner_delimiter_set const
        lines =  { NB_ELEMS(eols), eols, false },
        eq = { NB_ELEMS(cols), cols, true };

    struct liner liner, tokenizer;

    liner_init(&liner, &lines, (char const *)packet, packet_len);

    // Parse header fields
    while (true) {
        // Next line
        if (liner_eof(&liner)) break;

        // Otherwise tokenize the header line
        liner_init(&tokenizer, &eq, liner.start, liner_tok_length(&liner));

        for (unsigned f = 0; f < sdper->nb_fields; f++) {
            struct sdper_field const *field = sdper->fields + f;

            size_t len = liner_tok_length(&tokenizer);
            if (len != field->length)
              continue;

            if (0 != strncasecmp(field->name, tokenizer.start, len)) continue;

            SLOG(LOG_DEBUG, "Found field %s", field->name);
            liner_next(&tokenizer);
            int ret = field->cb(f, &tokenizer, user_data);
            if (ret) return ret;
            break;
        }

        liner_next(&liner);
    }

    if (head_sz) *head_sz = liner_parsed(&liner);
    return 0;
}
Exemplo n.º 2
0
enum proto_parse_status httper_parse(struct httper const *httper, size_t *head_sz, uint8_t const *packet, size_t packet_len, void *user_data)
{
    struct liner liner, tokenizer;
    bool found = false;

    for (unsigned c = 0; c < httper->nb_commands; c++) {
        struct httper_command const *const cmd = httper->commands + c;

        // Start by looking for the command before tokenizing (tokenizing takes too much time on random traffic)
        if (0 != strncmp(cmd->name, (char const *)packet, MIN(packet_len, cmd->len))) continue;
        if (packet_len < cmd->len) return PROTO_TOO_SHORT;

        liner_init(&liner, &delim_lines, (char const *)packet, packet_len);
        liner_init(&tokenizer, &delim_blanks, liner.start, liner_tok_length(&liner));

        if (liner_tok_length(&tokenizer) != cmd->len) {
no_command:
            SLOG(LOG_DEBUG, "Cannot find command");
            return PROTO_PARSE_ERR;
        }
        SLOG(LOG_DEBUG, "Found command %s", cmd->name);
        liner_next(&tokenizer);
        int ret = cmd->cb(c, &tokenizer, user_data);
        if (ret) return PROTO_PARSE_ERR;

        found = true;
        break;
    }

    if (! found) goto no_command;

    // Parse header fields
    unsigned nb_hdr_lines = 0;

    int field_idx = -1;
    char const *field_end = NULL;

    while (true) {
        // Next line
        bool const has_newline = liner.delim_size > 0;
        liner_next(&liner);
        if (liner_eof(&liner)) {
            // As an accommodation to old HTTP implementations, we allow a single line command
            // FIXME: check line termination with "*/x.y" ?
            if (nb_hdr_lines == 0 && has_newline) break;
            return PROTO_TOO_SHORT;
        }

        // If empty line we reached the end of the headers
        if (liner_tok_length(&liner) == 0) break;

        // Check if we reached the end of a multiline field.
        // FIXME: Is isspace appropriate here?
        if (! isspace(liner.start[0])) {
            if (field_idx >= 0) {
                liner_grow(&tokenizer, field_end);
                // Absorb all remaining of line onto this token
                liner_expand(&tokenizer);
                int ret = httper->fields[field_idx].cb(field_idx, &tokenizer, user_data);
                if (ret) return PROTO_PARSE_ERR;
            }

            // Tokenize the header line
            liner_init(&tokenizer, &delim_colons, liner.start, liner_tok_length(&liner));

            field_idx = -1;
            for (unsigned f = 0; f < httper->nb_fields; f++) {
                struct httper_field const *field = httper->fields + f;

                if (liner_tok_length(&tokenizer) < field->len) continue;
                if (0 != strncasecmp(field->name, tokenizer.start, liner_tok_length(&tokenizer))) continue;

                SLOG(LOG_DEBUG, "Found field %s", field->name);
                liner_next(&tokenizer);
                field_idx = f;
                break;
            }
        }
        field_end = liner.start + liner.tok_size;   // save end of line position in field_end
        nb_hdr_lines ++;
    }

    if (field_idx >= 0) {
        liner_grow(&tokenizer, field_end);
        // Absorb all remaining of line onto this token
        liner_expand(&tokenizer);
        int ret = httper->fields[field_idx].cb(field_idx, &tokenizer, user_data);
        if (ret) return PROTO_PARSE_ERR;
    }

    if (head_sz) *head_sz = liner_parsed(&liner);
    return PROTO_OK;
}