CHttpJob.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include <LibCore/CHttpJob.h>
  2. #include <LibCore/CHttpResponse.h>
  3. #include <LibCore/CTCPSocket.h>
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. CHttpJob::CHttpJob(const CHttpRequest& request)
  7. : m_request(request)
  8. {
  9. }
  10. CHttpJob::~CHttpJob()
  11. {
  12. }
  13. void CHttpJob::on_socket_connected()
  14. {
  15. auto raw_request = m_request.to_raw_request();
  16. #if 0
  17. printf("raw_request:\n%s\n", String::copy(raw_request).characters());
  18. #endif
  19. bool success = m_socket->send(raw_request);
  20. if (!success)
  21. return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::TransmissionFailed); });
  22. Vector<u8> buffer;
  23. while (m_socket->is_connected()) {
  24. if (m_state == State::InStatus) {
  25. while (!m_socket->can_read_line())
  26. usleep(1);
  27. ASSERT(m_socket->can_read_line());
  28. auto line = m_socket->read_line(PAGE_SIZE);
  29. if (line.is_null()) {
  30. printf("Expected HTTP status\n");
  31. return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::TransmissionFailed); });
  32. }
  33. auto parts = String::copy(line, Chomp).split(' ');
  34. if (parts.size() < 3) {
  35. printf("Expected 3-part HTTP status, got '%s'\n", line.pointer());
  36. return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::ProtocolFailed); });
  37. }
  38. bool ok;
  39. m_code = parts[1].to_uint(ok);
  40. if (!ok) {
  41. printf("Expected numeric HTTP status\n");
  42. return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::ProtocolFailed); });
  43. }
  44. m_state = State::InHeaders;
  45. continue;
  46. }
  47. if (m_state == State::InHeaders) {
  48. while (!m_socket->can_read_line())
  49. usleep(1);
  50. auto line = m_socket->read_line(PAGE_SIZE);
  51. if (line.is_null()) {
  52. printf("Expected HTTP header\n");
  53. return did_fail(CNetworkJob::Error::ProtocolFailed);
  54. }
  55. auto chomped_line = String::copy(line, Chomp);
  56. if (chomped_line.is_empty()) {
  57. m_state = State::InBody;
  58. continue;
  59. }
  60. auto parts = chomped_line.split(':');
  61. if (parts.is_empty()) {
  62. printf("Expected HTTP header with key/value\n");
  63. return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::ProtocolFailed); });
  64. }
  65. auto name = parts[0];
  66. if (chomped_line.length() < name.length() + 2) {
  67. printf("Malformed HTTP header: '%s' (%d)\n", chomped_line.characters(), chomped_line.length());
  68. return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::ProtocolFailed); });
  69. }
  70. auto value = chomped_line.substring(name.length() + 2, chomped_line.length() - name.length() - 2);
  71. m_headers.set(name, value);
  72. printf("[%s] = '%s'\n", name.characters(), value.characters());
  73. continue;
  74. }
  75. ASSERT(m_state == State::InBody);
  76. while (!m_socket->can_read())
  77. usleep(1);
  78. ASSERT(m_socket->can_read());
  79. auto payload = m_socket->receive(PAGE_SIZE);
  80. if (!payload) {
  81. if (m_socket->eof()) {
  82. m_state = State::Finished;
  83. break;
  84. }
  85. return deferred_invoke([this](auto&) { did_fail(CNetworkJob::Error::ProtocolFailed); });
  86. }
  87. buffer.append(payload.pointer(), payload.size());
  88. bool ok;
  89. if (buffer.size() >= m_headers.get("Content-Length").to_int(ok) && ok) {
  90. m_state = State::Finished;
  91. break;
  92. }
  93. }
  94. auto response = CHttpResponse::create(m_code, move(m_headers), ByteBuffer::copy(buffer.data(), buffer.size()));
  95. deferred_invoke([this, response](auto&) {
  96. did_finish(move(response));
  97. });
  98. }
  99. void CHttpJob::start()
  100. {
  101. ASSERT(!m_socket);
  102. m_socket = new CTCPSocket(this);
  103. m_socket->on_connected = [this] {
  104. printf("Socket on_connected callback\n");
  105. on_socket_connected();
  106. };
  107. bool success = m_socket->connect(m_request.hostname(), m_request.port());
  108. if (!success)
  109. return did_fail(CNetworkJob::Error::ConnectionFailed);
  110. }