summaryrefslogtreecommitdiff
path: root/te-parser.c
blob: 507038b01b728eadcd0f35be346d62f77d57af6e (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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include "internal.h"

//
// transfer encoding buffer functions
//

static void
fhp_te_parser_buf_flush(fhp_te_parser_t * const te) {
  te->buf_hash = fhp_lc_hash_push(te->buf_hash, te->buf, te->len);
  te->len = 0;
}

static void
fhp_te_parser_buf_push(
  fhp_te_parser_t * const te,
  uint8_t byte
) {
  // flush buffer (if necessary)
  if (te->len + 1 >= FHP_TE_MAX_BUF_SIZE)
    fhp_te_parser_buf_flush(te);

  // push to buffer
  te->buf[te->len] = byte;
  te->len++;
}

//
// transfer encoding parser functions
//

static const fhp_te_parser_t FHP_DEFAULT_TE_PARSER = {
  .state = FHP_TE_STATE_INIT,
  .len = 0,
  .num_tes = 0,
  .err = FHP_OK,
};

fhp_err_t
fhp_te_parser_init(fhp_te_parser_t * const te) {
  // init parser
  *te = FHP_DEFAULT_TE_PARSER;

  // return succes
  return FHP_OK;
}

static fhp_err_t
fhp_te_parser_push_byte(
  fhp_te_parser_t * const te,
  uint8_t byte
) {
retry:
  switch (te->state) {
  case FHP_TE_STATE_INIT:
    // set state
    te->state = FHP_TE_STATE_SPACE;
    goto retry;

    break;
  case FHP_TE_STATE_NAME:
    switch (byte) {
    CASE_TE_CHARS
      // add to buffer
      fhp_te_parser_buf_push(te, byte);

      break;
    CASE_OWS_CHARS
      // flush buffer (if necessary)
      if (te->len > 0)
        fhp_te_parser_buf_flush(te);

      // check number of encodings
      if (te->num_tes + 1 >= FHP_TE_MAX_TES)
        return FHP_ERR_TOO_MANY_TES;

      // add to list of transfer encodings
      // FIXME: check length
      te->tes[te->num_tes] = te->buf_hash;
      te->num_tes++;

      // set state
      te->state = FHP_TE_STATE_IGNORE_UNTIL_COMMA;

      break;
    case ',':
      // flush buffer (if necessary)
      if (te->len > 0)
        fhp_te_parser_buf_flush(te);

      // check number of encodings
      if (te->num_tes + 1 >= FHP_TE_MAX_TES)
        return FHP_ERR_TOO_MANY_TES;

      // add to list of transfer encodings
      // FIXME: check length
      te->tes[te->num_tes] = te->buf_hash;
      te->num_tes++;

      // set state
      te->state = FHP_TE_STATE_SPACE;

      break;
    default:
      // invalid transfer encoding character
      return FHP_ERR_INVALID_CHAR_IN_TE_NAME;
    }

    break;
  case FHP_TE_STATE_IGNORE_UNTIL_COMMA:
    switch (byte) {
    case ',':
      // set state
      te->state = FHP_TE_STATE_SPACE;

      break;
    default:
      // do nothing (ignore)
      NULL;
    }

    break;
  case FHP_TE_STATE_SPACE:
    switch (byte) {
    CASE_OWS_CHARS
      // ignore leading spaces
      break;
    CASE_TE_CHARS
      // clear buffer, init hash
      te->len = 0;
      te->buf_hash = fhp_hash_init();

      // set state
      te->state = FHP_TE_STATE_NAME;
      goto retry;

      break;
    default:
      // return error
      return FHP_ERR_INVALID_CHAR_IN_TE;
    }

    break;
  case FHP_TE_STATE_ERROR:
    // return last error
    return te->err;

    break;
  case FHP_TE_STATE_DONE:
    // shouldn't be reached
    return FHP_ERR_TE_PARSER_DONE;

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

  // return succes
  return FHP_OK;
}

fhp_err_t
fhp_te_parser_push(
  fhp_te_parser_t *te,
  uint8_t * const buf,
  size_t len
) {
  for (size_t i = 0; i < len; i++) {
    // push byte
    fhp_err_t err = fhp_te_parser_push_byte(te, buf[len]);

    // check error
    if (err != FHP_OK) {
      // cache error
      te->err = err;

      // set state
      te->state = FHP_TE_STATE_ERROR;

      // return error
      return err;
    }
  }

  // return succes
  return FHP_OK;
}

fhp_err_t
fhp_te_parser_done(fhp_te_parser_t * const te) {
  uint8_t buf[1] = { 20 };

  // flush data, check for error
  fhp_err_t err = fhp_te_parser_push(te, buf, 1);
  if (err != FHP_OK)
    return err;

  // set state
  te->state = FHP_TE_STATE_DONE;

  // return success
  return FHP_OK;
}