summaryrefslogtreecommitdiff
path: root/src/http_resp_parser.y
blob: dfbc18c3bc2248f1e16b11e58eb2fb2de9482dba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
%token_prefix TK_
%token_type {buffer *}
%extra_argument {http_resp_ctx_t *ctx}
%name http_resp_parser

%include {
#include <assert.h>
#include <string.h>
#include "http_resp.h"
#include "keyvalue.h"
#include "array.h"
#include "log.h"
}

%parse_failure {
  ctx->ok = 0;
}

%type protocol { int }
%type response_hdr { http_resp * }
%type number { int }
%type headers { array * }
%type header { data_string * }
%destructor reason { buffer_free($$); }
%token_destructor { buffer_free($$); }

/* just headers + Status: ... */
response_hdr ::= headers(HDR) CRLF . {
    http_resp *resp = ctx->resp;
    data_string *ds;
 
    resp->protocol = HTTP_VERSION_UNSET;

    buffer_copy_string(resp->reason, ""); /* no reason */
    array_free(resp->headers);
    resp->headers = HDR;

    if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) { 
        resp->status = 0;
    } else {
        char *err;
        resp->status = strtol(ds->value->ptr, &err, 10);
   
        if (*err != '\0' && *err != ' ') {
            buffer_copy_string(ctx->errmsg, "expected a number: ");
            buffer_append_string_buffer(ctx->errmsg, ds->value);
            buffer_append_string(ctx->errmsg, err);
        
            ctx->ok = 0;
        }
    }

    HDR = NULL;
}
/* HTTP/1.0 <status> ... */
response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
    http_resp *resp = ctx->resp;
    
    resp->status = C;
    resp->protocol = B;
    buffer_copy_string_buffer(resp->reason, D);
    buffer_free(D); 

    array_free(resp->headers);
    
    resp->headers = HDR;
}

protocol(A) ::= STRING(B). {
    if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
        A = HTTP_VERSION_1_0;
    } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
        A = HTTP_VERSION_1_1;
    } else {
        buffer_copy_string(ctx->errmsg, "unknown protocol: ");
        buffer_append_string_buffer(ctx->errmsg, B);
        
        ctx->ok = 0;
    }
    buffer_free(B);
}

number(A) ::= STRING(B). {
    char *err;
    A = strtol(B->ptr, &err, 10);
    
    if (*err != '\0') {
        buffer_copy_string(ctx->errmsg, "expected a number, got: ");
        buffer_append_string_buffer(ctx->errmsg, B);
        
        ctx->ok = 0;
    }
    buffer_free(B);
}

reason(A) ::= STRING(B). {
    A = B;
}

reason(A) ::= reason(C) STRING(B). {
    A = C;
    
    buffer_append_string(A, " ");
    buffer_append_string_buffer(A, B);

    buffer_free(B); 
}

headers(HDRS) ::= headers(SRC) header(HDR). {
    HDRS = SRC;
    
    array_insert_unique(HDRS, (data_unset *)HDR);
}

headers(HDRS) ::= header(HDR). {
    HDRS = array_init();

    array_insert_unique(HDRS, (data_unset *)HDR);
}
header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
    HDR = data_string_init();
    
    buffer_copy_string_buffer(HDR->key, A);
    buffer_copy_string_buffer(HDR->value, B);    
    buffer_free(A);
    buffer_free(B);
}