summaryrefslogtreecommitdiff
path: root/header-value-parser.c
blob: d8998897cc1962b797e56735a8dc9da71e6a8b88 (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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include "internal.h"

//
// header value parser
//

fhp_err_t
fhp_header_value_parser_init(fhp_ctx_t * const ctx) {
  uint32_t hash = ctx->header_name_hash;
  fhp_header_value_parser_t parser = FHP_HEADER_VALUE_PARSER_NONE;
  fhp_err_t err;

  /* fprintf(
    stderr,
    "hashes: header = %u, env = %u, str = %u, str(lc) = %u\n",
    hash,
    fhp->env->hashes[FHP_STR_TRANSFER_ENCODING],
    fhp_hash_string("Transfer-Encoding"),
    fhp_lc_hash_string("Transfer-Encoding")
  ); */

  if (hash == ctx->env->hashes[FHP_STR_TRANSFER_ENCODING]) {
    // set parser type
    parser = FHP_HEADER_VALUE_PARSER_TRANSFER_ENCODING;

    // init parser
    if ((err = fhp_te_parser_init(&(ctx->parsers.te))) != FHP_OK)
      return err;
  } else if (hash == ctx->env->hashes[FHP_STR_CONTENT_LENGTH]) {
    // set parser type
    parser = FHP_HEADER_VALUE_PARSER_CONTENT_LENGTH;

    // init parser
    if ((err = fhp_cl_parser_init(&(ctx->parsers.cl))) != FHP_OK)
      return err;
  } else if (hash == ctx->env->hashes[FHP_STR_CONTENT_TYPE]) {
    // set parser type
    parser = FHP_HEADER_VALUE_PARSER_CONTENT_TYPE;

    // init parser
    if ((err = fhp_ct_parser_init(&(ctx->parsers.ct), ctx->env)) != FHP_OK)
      return err;
  } else {
    // set default parser type
    parser = FHP_HEADER_VALUE_PARSER_NONE;
  }

  // set value parser
  ctx->header_value_parser = parser;

  // return success
  return FHP_OK;
}

fhp_err_t
fhp_header_value_parser_push(
  fhp_ctx_t * const ctx,
  uint8_t * const buf,
  size_t len
) {
  fhp_err_t r = FHP_OK;

  switch (ctx->header_value_parser) {
  case FHP_HEADER_VALUE_PARSER_TRANSFER_ENCODING:
    r = fhp_te_parser_push(&(ctx->parsers.te), buf, len);
    break;
  case FHP_HEADER_VALUE_PARSER_CONTENT_LENGTH:
    r = fhp_cl_parser_push(&(ctx->parsers.cl), buf, len);
    break;
  case FHP_HEADER_VALUE_PARSER_CONTENT_TYPE:
    r = fhp_ct_parser_push(&(ctx->parsers.ct), buf, len);
    break;
  default:
    // do nothing
    r = FHP_OK;
    break;
  }

  // return result
  return r;
}

fhp_err_t
fhp_header_value_parser_done(fhp_ctx_t * const ctx) {
  fhp_err_t r = FHP_OK;

  switch (ctx->header_value_parser) {
  case FHP_HEADER_VALUE_PARSER_TRANSFER_ENCODING:
    // finish parsing tes
    if ((r = fhp_te_parser_done(&(ctx->parsers.te), &(ctx->num_tes))) != FHP_OK)
      return r;

    // check number of tes
    if (ctx->num_tes > FHP_CTX_MAX_TRANSFER_ENCODINGS)
      return FHP_ERR_TOO_MANY_TES;

    // copy tes to context
    if ((r = fhp_te_parser_get_tes(&(ctx->parsers.te), ctx->tes, FHP_CTX_MAX_TRANSFER_ENCODINGS)) != FHP_OK)
      return r;

    // update body type
    // FIXME: follow RFC7230 3.3.3
    // https://tools.ietf.org/html/rfc7230#section-3.3.3
    switch (ctx->body_type) {
    case FHP_BODY_TYPE_NONE:
      // set body type
      ctx->body_type = FHP_BODY_TYPE_CONTENT_LENGTH;

      break;
    case FHP_BODY_TYPE_CONTENT_LENGTH:
      // duplicate content-length
      // FIXME: should print warning here

      break;
    case FHP_BODY_TYPE_TRANSFER_ENCODING:
      // already have transfer-encoding, ignore content-length
      // FIXME: should print warning here

      break;
    default:
      // never reached
      return FHP_ERR_INVALID_BODY_TYPE;
    }

    // notify callback
    if (!ctx->cb(ctx, FHP_TOKEN_HEADER_TRANSFER_ENCODING, 0, 0))
      return FHP_ERR_CB;

    break;
  case FHP_HEADER_VALUE_PARSER_CONTENT_LENGTH:
    // finish parsing content-length and copy to context
    if ((r = fhp_cl_parser_done(&(ctx->parsers.cl), &(ctx->content_length))) != FHP_OK)
      return r;

    // update body type
    // FIXME: follow RFC7230 3.3.3
    // https://tools.ietf.org/html/rfc7230#section-3.3.3
    switch (ctx->body_type) {
    case FHP_BODY_TYPE_NONE:
      // set body type
      ctx->body_type = FHP_BODY_TYPE_CONTENT_LENGTH;

      break;
    case FHP_BODY_TYPE_CONTENT_LENGTH:
      // both content-type and transfer-encoding, ignore content-type
      // FIXME: should print warning here

      break;
    case FHP_BODY_TYPE_TRANSFER_ENCODING:
      // duplicate transfer-encoding
      // FIXME: should print warnings

      break;
    default:
      // never reached
      return FHP_ERR_INVALID_BODY_TYPE;
    }

    // notify callback
    if (!ctx->cb(ctx, FHP_TOKEN_HEADER_CONTENT_LENGTH, 0, 0))
      return FHP_ERR_CB;

    break;
  case FHP_HEADER_VALUE_PARSER_CONTENT_TYPE:
    // finish parsing content-length and copy to context
    if ((r = fhp_ct_parser_done(&(ctx->parsers.ct), &(ctx->content_type))) != FHP_OK)
      return r;

    // notify callback
    if (!ctx->cb(ctx, FHP_TOKEN_HEADER_CONTENT_TYPE, 0, 0))
      return FHP_ERR_CB;

  default:
    // do nothing
    r = FHP_OK;

    break;
  }

  // clear header value parser
  ctx->header_value_parser = FHP_HEADER_VALUE_PARSER_NONE;

  // return result
  return r;
}