379{
380 if (m_recv_all_headers) {
381 m_recv_all_headers = false;
382 m_recv_status_line = false;
383 }
384
385 if (!m_recv_status_line) {
386 m_recv_status_line = true;
387
388 std::stringstream ss(header_line);
389 std::string item;
390 if (!std::getline(ss, item, ' ')) return false;
391 m_resp_protocol = item;
392 if (!std::getline(ss, item, ' ')) return false;
393 try {
394 m_status_code = std::stol(item);
395 } catch (...) {
396 return false;
397 }
398 if (m_status_code < 100 || m_status_code >= 600) {
399 return false;
400 }
401 if (!std::getline(ss, item, '\n')) return false;
402 auto cr_loc = item.find('\r');
403 if (cr_loc != std::string::npos) {
404 m_resp_message = item.substr(0, cr_loc);
405 } else {
406 m_resp_message = item;
407 }
408 return true;
409 }
410
411 if (header_line.empty() || header_line == "\n" || header_line == "\r\n") {
412 m_recv_all_headers = true;
413 return true;
414 }
415
416 auto found = header_line.find(":");
417 if (found == std::string::npos) {
418 return false;
419 }
420
421 std::string header_name = header_line.substr(0, found);
423 return false;
424 }
425
426 found += 1;
427 while (found < header_line.size()) {
428 if (header_line[found] != ' ') {break;}
429 found += 1;
430 }
431 std::string header_value = header_line.substr(found);
432
433
434 header_value.erase(header_value.find_last_not_of(" \r\n\t") + 1);
435
436
437
438 auto iter = m_headers.find(header_name);
439 if (iter == m_headers.end()) {
440 m_headers.insert(iter, {header_name, {header_value}});
441 } else {
442 iter->second.push_back(header_value);
443 }
444
445 if (header_name == "Allow") {
446 std::string_view val(header_value);
447 while (!val.empty()) {
448 auto found = val.find(',');
449 auto method = val.substr(0, found);
450 if (method == "PROPFIND") {
453 }
454 if (found == std::string_view::npos) break;
455 val = val.substr(found + 1);
456 }
459 }
460 } else if (header_name == "Content-Length") {
461 try {
462 m_content_length = std::stoll(header_value);
463 } catch (...) {
464 return false;
465 }
466 }
467 else if (header_name == "Content-Type") {
468 std::string_view val(header_value);
469 auto found = val.find(";");
470 auto first_type = val.substr(0, found);
471 m_multipart_byteranges = first_type == "multipart/byteranges";
472 if (m_multipart_byteranges) {
473 auto remainder = val.substr(found + 1);
474 found = remainder.find("boundary=");
475 if (found != std::string_view::npos) {
477 }
478 }
479 }
480 else if (header_name == "Content-Range") {
481 auto found = header_value.find(" ");
482 if (found == std::string::npos) {
483 return false;
484 }
485 std::string range_unit = header_value.substr(0, found);
486 if (range_unit != "bytes") {
487 return false;
488 }
489 auto range_resp = header_value.substr(found + 1);
490 found = range_resp.find("/");
491 if (found == std::string::npos) {
492 return false;
493 }
494 auto incl_range = range_resp.substr(0, found);
495 found = incl_range.find("-");
496 if (found == std::string::npos) {
497 return false;
498 }
499 auto first_pos = incl_range.substr(0, found);
500 try {
501 m_response_offset = std::stoll(first_pos);
502 } catch (...) {
503 return false;
504 }
505 auto last_pos = incl_range.substr(found + 1);
506 size_t last_byte;
507 try {
508 last_byte = std::stoll(last_pos);
509 } catch (...) {
510 return false;
511 }
512 m_content_length = last_byte - m_response_offset + 1;
513 }
514 else if (header_name == "Location") {
515 m_location = header_value;
516 } else if (header_name == "Digest") {
518 }
519 else if (header_name == "Etag")
520 {
521
522
523 m_etag = header_value;
524 m_etag.erase(remove(m_etag.begin(), m_etag.end(), '\"'), m_etag.end());
525 }
526 else if (header_name == "Cache-Control")
527 {
528 m_cache_control = header_value;
529 }
530
531 return true;
532}