HttpResponseWriter.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #ifndef HV_HTTP_RESPONSE_WRITER_H_
  2. #define HV_HTTP_RESPONSE_WRITER_H_
  3. #include "Channel.h"
  4. #include "HttpMessage.h"
  5. namespace hv {
  6. class HttpResponseWriter : public SocketChannel {
  7. public:
  8. HttpResponsePtr response;
  9. enum State {
  10. SEND_BEGIN = 0,
  11. SEND_HEADER,
  12. SEND_BODY,
  13. SEND_CHUNKED,
  14. SEND_CHUNKED_END,
  15. SEND_END,
  16. } state: 8, end: 8;
  17. HttpResponseWriter(hio_t* io, const HttpResponsePtr& resp)
  18. : SocketChannel(io)
  19. , response(resp)
  20. , state(SEND_BEGIN)
  21. , end(SEND_BEGIN)
  22. {}
  23. ~HttpResponseWriter() {}
  24. // Begin -> End
  25. // Begin -> WriteResponse -> End
  26. // Begin -> WriteStatus -> WriteHeader -> WriteBody -> End
  27. // Begin -> EndHeaders("Content-Type", "text/event-stream") -> write -> write -> ... -> close
  28. // Begin -> EndHeaders("Content-Length", content_length) -> WriteBody -> WriteBody -> ... -> End
  29. // Begin -> EndHeaders("Transfer-Encoding", "chunked") -> WriteChunked -> WriteChunked -> ... -> End
  30. int Begin() {
  31. state = end = SEND_BEGIN;
  32. return 0;
  33. }
  34. int WriteStatus(http_status status_codes) {
  35. response->status_code = status_codes;
  36. return 0;
  37. }
  38. int WriteHeader(const char* key, const char* value) {
  39. response->SetHeader(key, value);
  40. return 0;
  41. }
  42. template<typename T>
  43. int WriteHeader(const char* key, T num) {
  44. response->SetHeader(key, hv::to_string(num));
  45. return 0;
  46. }
  47. int WriteCookie(const HttpCookie& cookie) {
  48. response->cookies.push_back(cookie);
  49. return 0;
  50. }
  51. int EndHeaders(const char* key = NULL, const char* value = NULL) {
  52. if (state != SEND_BEGIN) return -1;
  53. if (key && value) {
  54. response->SetHeader(key, value);
  55. }
  56. std::string headers = response->Dump(true, false);
  57. state = SEND_HEADER;
  58. return write(headers);
  59. }
  60. template<typename T>
  61. int EndHeaders(const char* key, T num) {
  62. std::string value = hv::to_string(num);
  63. return EndHeaders(key, value.c_str());
  64. }
  65. int WriteChunked(const char* buf, int len = -1) {
  66. int ret = 0;
  67. if (len == -1) len = strlen(buf);
  68. if (state == SEND_BEGIN) {
  69. EndHeaders("Transfer-Encoding", "chunked");
  70. }
  71. char chunked_header[64];
  72. int chunked_header_len = snprintf(chunked_header, sizeof(chunked_header), "%x\r\n", len);
  73. write(chunked_header, chunked_header_len);
  74. if (buf && len) {
  75. state = SEND_CHUNKED;
  76. ret = write(buf, len);
  77. } else {
  78. state = SEND_CHUNKED_END;
  79. }
  80. write("\r\n", 2);
  81. return ret;
  82. }
  83. int WriteChunked(const std::string& str) {
  84. return WriteChunked(str.c_str(), str.size());
  85. }
  86. int EndChunked() {
  87. return WriteChunked(NULL, 0);
  88. }
  89. int WriteBody(const char* buf, int len = -1) {
  90. if (response->IsChunked()) {
  91. return WriteChunked(buf, len);
  92. }
  93. if (len == -1) len = strlen(buf);
  94. if (state == SEND_BEGIN) {
  95. response->body.append(buf, len);
  96. return len;
  97. } else {
  98. state = SEND_BODY;
  99. return write(buf, len);
  100. }
  101. }
  102. int WriteBody(const std::string& str) {
  103. return WriteBody(str.c_str(), str.size());
  104. }
  105. int WriteResponse(HttpResponse* resp) {
  106. if (resp == NULL) {
  107. response->status_code = HTTP_STATUS_INTERNAL_SERVER_ERROR;
  108. return 0;
  109. }
  110. bool is_dump_headers = state == SEND_BEGIN ? true : false;
  111. std::string msg = resp->Dump(is_dump_headers, true);
  112. state = SEND_BODY;
  113. return write(msg);
  114. }
  115. int SSEvent(const std::string& data, const char* event = "message") {
  116. if (state == SEND_BEGIN) {
  117. EndHeaders("Content-Type", "text/event-stream");
  118. }
  119. std::string msg;
  120. msg = "event: "; msg += event; msg += "\n";
  121. msg += "data: "; msg += data; msg += "\n\n";
  122. state = SEND_BODY;
  123. return write(msg);
  124. }
  125. int End(const char* buf = NULL, int len = -1) {
  126. if (end == SEND_END) return 0;
  127. end = SEND_END;
  128. if (!isConnected()) {
  129. return -1;
  130. }
  131. int ret = 0;
  132. bool keepAlive = response->IsKeepAlive();
  133. if (state == SEND_CHUNKED) {
  134. if (buf) {
  135. ret = WriteChunked(buf, len);
  136. }
  137. if (state == SEND_CHUNKED) {
  138. EndChunked();
  139. }
  140. } else {
  141. if (buf) {
  142. ret = WriteBody(buf, len);
  143. }
  144. bool is_dump_headers = true;
  145. bool is_dump_body = true;
  146. if (state == SEND_HEADER) {
  147. is_dump_headers = false;
  148. } else if (state == SEND_BODY) {
  149. is_dump_headers = false;
  150. is_dump_body = false;
  151. }
  152. if (is_dump_body) {
  153. std::string msg = response->Dump(is_dump_headers, is_dump_body);
  154. state = SEND_BODY;
  155. ret = write(msg);
  156. }
  157. }
  158. if (!keepAlive) {
  159. close(true);
  160. }
  161. return ret;
  162. }
  163. int End(const std::string& str) {
  164. return End(str.c_str(), str.size());
  165. }
  166. };
  167. }
  168. typedef std::shared_ptr<hv::HttpResponseWriter> HttpResponseWriterPtr;
  169. #endif // HV_HTTP_RESPONSE_WRITER_H_