Class: Raptor::HttpParser

Inherits:
Object
  • Object
show all
Defined in:
ext/raptor_http/raptor_http.c

Constant Summary collapse

MAX_CHUNK_OVERHEAD =
INT2FIX(MAX_CHUNK_OVERHEAD)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.chunked_encode(buffer, chunk) ⇒ Object



1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
# File 'ext/raptor_http/raptor_http.c', line 1476

static VALUE parser_chunked_encode(VALUE self, VALUE buffer, VALUE chunk) {
  Check_Type(buffer, T_STRING);
  Check_Type(chunk, T_STRING);
  long chunk_len = RSTRING_LEN(chunk);
  if (chunk_len == 0) return buffer;

  char hex_buf[17];
  int hex_len = snprintf(hex_buf, sizeof(hex_buf), "%lx", (unsigned long)chunk_len);
  rb_str_cat(buffer, hex_buf, hex_len);
  rb_str_cat(buffer, "\r\n", 2);
  rb_str_cat(buffer, RSTRING_PTR(chunk), chunk_len);
  rb_str_cat(buffer, "\r\n", 2);
  return buffer;
}

.decode_chunked(*args) ⇒ Object

pipelined request that follows it.



1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
# File 'ext/raptor_http/raptor_http.c', line 1312

static VALUE parser_decode_chunked(int argc, VALUE *argv, VALUE self) {
  VALUE buffer, max_size;
  rb_scan_args(argc, argv, "11", &buffer, &max_size);
  Check_Type(buffer, T_STRING);

  const char *buf = RSTRING_PTR(buffer);
  size_t len = (size_t)RSTRING_LEN(buffer);
  size_t offset = 0;
  size_t overhead = 0;
  int has_max = !NIL_P(max_size);
  size_t max_bytes = has_max ? NUM2SIZET(max_size) : 0;

  VALUE decoded = rb_str_buf_new((long)len);

  while (offset < len) {
    const char *crlf = find_crlf(buf + offset, len - offset);
    if (!crlf) return rb_ary_new_from_args(2, decoded, ID2SYM(id_incomplete));

    size_t line_len = (size_t)(crlf - (buf + offset));
    size_t size_len = line_len;
    for (size_t i = 0; i < line_len; i++) {
      if (buf[offset + i] == ';') { size_len = i; break; }
    }
    if (size_len == 0) return rb_ary_new_from_args(2, decoded, ID2SYM(id_malformed));

    uint64_t chunk_size = 0;
    for (size_t i = 0; i < size_len; i++) {
      char c = buf[offset + i];
      uint64_t digit;
      if (c >= '0' && c <= '9') digit = (uint64_t)(c - '0');
      else if (c >= 'a' && c <= 'f') digit = (uint64_t)(c - 'a' + 10);
      else if (c >= 'A' && c <= 'F') digit = (uint64_t)(c - 'A' + 10);
      else return rb_ary_new_from_args(2, decoded, ID2SYM(id_malformed));
      if (chunk_size > (UINT64_MAX >> 4)) return rb_ary_new_from_args(2, decoded, ID2SYM(id_malformed));
      chunk_size = (chunk_size << 4) | digit;
    }
    if (chunk_size > (uint64_t)(SIZE_MAX / 2)) return rb_ary_new_from_args(2, decoded, ID2SYM(id_malformed));

    size_t crlf_offset = offset + line_len;

    if (chunk_size == 0) {
      size_t trailer_offset = crlf_offset + 2;
      while (1) {
        if (trailer_offset >= len) return rb_ary_new_from_args(2, decoded, ID2SYM(id_incomplete));
        const char *tcrlf = find_crlf(buf + trailer_offset, len - trailer_offset);
        if (!tcrlf) return rb_ary_new_from_args(2, decoded, ID2SYM(id_incomplete));
        if (tcrlf == buf + trailer_offset) return rb_ary_new_from_args(3, decoded, ID2SYM(id_complete), SIZET2NUM(trailer_offset + 2));
        trailer_offset = (size_t)(tcrlf - buf) + 2;
      }
    }

    size_t decoded_len = (size_t)RSTRING_LEN(decoded);
    if (has_max && (decoded_len + (size_t)chunk_size) > max_bytes) {
      return rb_ary_new_from_args(2, decoded, ID2SYM(id_too_large));
    }

    overhead += line_len + 4;
    if (overhead > (decoded_len + (size_t)chunk_size + MAX_CHUNK_OVERHEAD)) {
      return rb_ary_new_from_args(2, decoded, ID2SYM(id_malformed));
    }

    size_t data_offset = crlf_offset + 2;
    size_t available = len > data_offset ? len - data_offset : 0;
    size_t bytes_to_copy = (size_t)chunk_size < available ? (size_t)chunk_size : available;
    rb_str_cat(decoded, buf + data_offset, (long)bytes_to_copy);

    offset = data_offset + (size_t)chunk_size + 2;
  }

  return rb_ary_new_from_args(2, decoded, ID2SYM(id_incomplete));
}

.format_headers(buffer, headers) ⇒ Object



1469
1470
1471
1472
1473
1474
# File 'ext/raptor_http/raptor_http.c', line 1469

static VALUE parser_format_headers(VALUE self, VALUE buffer, VALUE headers) {
  Check_Type(buffer, T_STRING);
  Check_Type(headers, T_HASH);
  rb_hash_foreach(headers, format_header_iter, buffer);
  return buffer;
}

.illegal_header_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


1411
1412
1413
1414
# File 'ext/raptor_http/raptor_http.c', line 1411

static VALUE parser_illegal_header_key_p(VALUE self, VALUE key) {
  Check_Type(key, T_STRING);
  return contains_illegal_byte(illegal_header_key_bitmap, RSTRING_PTR(key), (size_t)RSTRING_LEN(key)) ? Qtrue : Qfalse;
}

.illegal_header_value?(value) ⇒ Boolean

Returns:

  • (Boolean)


1416
1417
1418
1419
# File 'ext/raptor_http/raptor_http.c', line 1416

static VALUE parser_illegal_header_value_p(VALUE self, VALUE value) {
  Check_Type(value, T_STRING);
  return contains_illegal_byte(illegal_header_value_bitmap, RSTRING_PTR(value), (size_t)RSTRING_LEN(value)) ? Qtrue : Qfalse;
}

Instance Method Details

#chunked? ⇒ Boolean

Returns:

  • (Boolean)


1281
1282
1283
1284
1285
# File 'ext/raptor_http/raptor_http.c', line 1281

static VALUE parser_chunked_p(VALUE self) {
  raptor_parser *parser;
  TypedData_Get_Struct(self, raptor_parser, &parser_type, parser);
  return (parser->flags & FLAG_CHUNKED) ? Qtrue : Qfalse;
}

#content_length ⇒ Object



1287
1288
1289
1290
1291
# File 'ext/raptor_http/raptor_http.c', line 1287

static VALUE parser_content_length(VALUE self) {
  raptor_parser *parser;
  TypedData_Get_Struct(self, raptor_parser, &parser_type, parser);
  return LL2NUM(parser->content_len);
}

#execute(req_hash, buffer, start) ⇒ Object



1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
# File 'ext/raptor_http/raptor_http.c', line 1250

static VALUE parser_execute(VALUE self, VALUE req_hash, VALUE buffer, VALUE start) {
  raptor_parser *parser;
  TypedData_Get_Struct(self, raptor_parser, &parser_type, parser);

  Check_Type(buffer, T_STRING);
  parser->request = req_hash;

  size_t from = NUM2SIZET(start);
  const char *data = RSTRING_PTR(buffer);
  size_t len = RSTRING_LEN(buffer);

  if (from >= len)
    rb_raise(eHttpParserError, "start is after buffer end");

  raptor_parser_execute(parser, data + from, len - from);

  return SIZET2NUM(parser->nread);
}

#finished? ⇒ Boolean

Returns:

  • (Boolean)


1269
1270
1271
1272
1273
# File 'ext/raptor_http/raptor_http.c', line 1269

static VALUE parser_finished_p(VALUE self) {
  raptor_parser *parser;
  TypedData_Get_Struct(self, raptor_parser, &parser_type, parser);
  return (parser->flags & FLAG_FINISHED) ? Qtrue : Qfalse;
}

#has_body? ⇒ Boolean

Returns:

  • (Boolean)


1275
1276
1277
1278
1279
# File 'ext/raptor_http/raptor_http.c', line 1275

static VALUE parser_has_body_p(VALUE self) {
  raptor_parser *parser;
  TypedData_Get_Struct(self, raptor_parser, &parser_type, parser);
  return (parser->flags & FLAG_HAS_BODY) ? Qtrue : Qfalse;
}

#reset ⇒ Object



1293
1294
1295
1296
1297
1298
# File 'ext/raptor_http/raptor_http.c', line 1293

static VALUE parser_reset(VALUE self) {
  raptor_parser *parser;
  TypedData_Get_Struct(self, raptor_parser, &parser_type, parser);
  raptor_parser_init(parser);
  return Qnil;
}