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



1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
# File 'ext/raptor_http/raptor_http.c', line 1493

static VALUE parser_chunked_encode(VALUE self, VALUE buffer, VALUE chunk) {
  (void)self;
  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



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
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
# File 'ext/raptor_http/raptor_http.c', line 1334

static VALUE parser_decode_chunked(int argc, VALUE *argv, VALUE self) {
  (void)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(2, decoded, ID2SYM(id_complete));
        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



1485
1486
1487
1488
1489
1490
1491
# File 'ext/raptor_http/raptor_http.c', line 1485

static VALUE parser_format_headers(VALUE self, VALUE buffer, VALUE headers) {
  (void)self;
  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)


1422
1423
1424
1425
1426
# File 'ext/raptor_http/raptor_http.c', line 1422

static VALUE parser_illegal_header_key_p(VALUE self, VALUE key) {
  (void)self;
  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)


1428
1429
1430
1431
1432
# File 'ext/raptor_http/raptor_http.c', line 1428

static VALUE parser_illegal_header_value_p(VALUE self, VALUE value) {
  (void)self;
  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

#bodyObject



1319
1320
1321
1322
1323
# File 'ext/raptor_http/raptor_http.c', line 1319

static VALUE parser_body(VALUE self) {
  raptor_parser *parser;
  TypedData_Get_Struct(self, raptor_parser, &parser_type, parser);
  return parser->body;
}

#chunked?Boolean

Returns:

  • (Boolean)


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

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

#content_lengthObject



1300
1301
1302
1303
1304
# File 'ext/raptor_http/raptor_http.c', line 1300

static VALUE parser_content_length(VALUE self) {
  raptor_parser *parser;
  TypedData_Get_Struct(self, raptor_parser, &parser_type, parser);
  return SIZET2NUM(raptor_parser_content_length(parser));
}

#execute(req_hash, buffer, start) ⇒ Object



1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
# File 'ext/raptor_http/raptor_http.c', line 1263

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)


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

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

#has_body?Boolean

Returns:

  • (Boolean)


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

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

#nreadObject



1306
1307
1308
1309
1310
# File 'ext/raptor_http/raptor_http.c', line 1306

static VALUE parser_nread(VALUE self) {
  raptor_parser *parser;
  TypedData_Get_Struct(self, raptor_parser, &parser_type, parser);
  return SIZET2NUM(parser->nread);
}

#resetObject



1312
1313
1314
1315
1316
1317
# File 'ext/raptor_http/raptor_http.c', line 1312

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