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