278{
279 if (m_recv_all_headers) {
280 m_recv_all_headers = false;
281 m_recv_status_line = false;
282 }
283
284 if (!m_recv_status_line) {
285 m_recv_status_line = true;
286
287 std::stringstream ss(header_line);
288 std::string item;
289 if (!std::getline(ss, item, ' ')) return false;
290 m_resp_protocol = item;
291 if (!std::getline(ss, item, ' ')) return false;
292 try {
293 m_status_code = std::stol(item);
294 } catch (...) {
295 return false;
296 }
297 if (m_status_code < 100 || m_status_code >= 600) {
298 return false;
299 }
300 if (!std::getline(ss, item, '\n')) return false;
301 auto cr_loc = item.find('\r');
302 if (cr_loc != std::string::npos) {
303 m_resp_message = item.substr(0, cr_loc);
304 } else {
305 m_resp_message = item;
306 }
307 return true;
308 }
309
310 if (header_line.empty() || header_line == "\n" || header_line == "\r\n") {
311 m_recv_all_headers = true;
312 return true;
313 }
314
315 auto found = header_line.find(":");
316 if (found == std::string::npos) {
317 return false;
318 }
319
320 std::string header_name = header_line.substr(0, found);
322 return false;
323 }
324
325 found += 1;
326 while (found < header_line.size()) {
327 if (header_line[found] != ' ') {break;}
328 found += 1;
329 }
330 std::string header_value = header_line.substr(found);
331
332
333 header_value.erase(header_value.find_last_not_of(" \r\n\t") + 1);
334
335
336
337 auto iter = m_headers.find(header_name);
338 if (iter == m_headers.end()) {
339 m_headers.insert(iter, {header_name, {header_value}});
340 } else {
341 iter->second.push_back(header_value);
342 }
343
344 if (header_name == "Allow") {
345 std::string_view val(header_value);
346 while (!val.empty()) {
347 auto found = val.find(',');
348 auto method = val.substr(0, found);
349 if (method == "PROPFIND") {
352 }
353 if (found == std::string_view::npos) break;
354 val = val.substr(found + 1);
355 }
358 }
359 } else if (header_name == "Content-Length") {
360 try {
361 m_content_length = std::stoll(header_value);
362 } catch (...) {
363 return false;
364 }
365 }
366 else if (header_name == "Content-Type") {
367 std::string_view val(header_value);
368 auto found = val.find(";");
369 auto first_type = val.substr(0, found);
370 m_multipart_byteranges = first_type == "multipart/byteranges";
371 if (m_multipart_byteranges) {
372 auto remainder = val.substr(found + 1);
373 found = remainder.find("boundary=");
374 if (found != std::string_view::npos) {
376 }
377 }
378 }
379 else if (header_name == "Content-Range") {
380 auto found = header_value.find(" ");
381 if (found == std::string::npos) {
382 return false;
383 }
384 std::string range_unit = header_value.substr(0, found);
385 if (range_unit != "bytes") {
386 return false;
387 }
388 auto range_resp = header_value.substr(found + 1);
389 found = range_resp.find("/");
390 if (found == std::string::npos) {
391 return false;
392 }
393 auto incl_range = range_resp.substr(0, found);
394 found = incl_range.find("-");
395 if (found == std::string::npos) {
396 return false;
397 }
398 auto first_pos = incl_range.substr(0, found);
399 try {
400 m_response_offset = std::stoll(first_pos);
401 } catch (...) {
402 return false;
403 }
404 auto last_pos = incl_range.substr(found + 1);
405 size_t last_byte;
406 try {
407 last_byte = std::stoll(last_pos);
408 } catch (...) {
409 return false;
410 }
411 m_content_length = last_byte - m_response_offset + 1;
412 }
413 else if (header_name == "Location") {
414 m_location = header_value;
415 } else if (header_name == "Digest") {
417 }
418 else if (header_name == "Etag")
419 {
420
421
422 m_etag = header_value;
423 m_etag.erase(remove(m_etag.begin(), m_etag.end(), '\"'), m_etag.end());
424 }
425 else if (header_name == "Cache-Control")
426 {
427 m_cache_control = header_value;
428 }
429
430 return true;
431}