1 // This may look like C code, but it's really -*- C++ -*- 2 /* 3 * Copyright (C) 2008 Emweb bv, Herent, Belgium. 4 * 5 * All rights reserved. 6 */ 7 // 8 // reply.hpp 9 // ~~~~~~~~~ 10 // 11 // Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) 12 // 13 // Distributed under the Boost Software License, Version 1.0. (See accompanying 14 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 15 // 16 17 #ifndef HTTP_REPLY_HPP 18 #define HTTP_REPLY_HPP 19 20 #include <time.h> 21 22 #include <list> 23 #include <string> 24 #include <vector> 25 26 #include <Wt/AsioWrapper/asio.hpp> 27 28 #ifdef WTHTTP_WITH_ZLIB 29 #include <zlib.h> 30 #endif 31 32 #include "Wt/WStringStream.h" 33 #include "Wt/WLogger.h" 34 #include "../web/Configuration.h" 35 36 #include "Buffer.h" 37 #include "WHttpDllDefs.h" 38 #include "Request.h" 39 40 namespace http { 41 namespace server { 42 43 namespace asio = Wt::AsioWrapper::asio; 44 45 class Configuration; 46 class Connection; 47 class Reply; 48 49 typedef std::shared_ptr<Connection> ConnectionPtr; 50 typedef std::shared_ptr<Reply> ReplyPtr; 51 52 class WTHTTP_API Reply : public std::enable_shared_from_this<Reply> 53 { 54 public: 55 Reply(Request& request, const Configuration& config); 56 virtual ~Reply(); 57 58 virtual void reset(const Wt::EntryPoint *ep); 59 60 enum status_type 61 { 62 no_status = 0, 63 switching_protocols = 101, 64 ok = 200, 65 created = 201, 66 accepted = 202, 67 no_content = 204, 68 partial_content = 206, 69 multiple_choices = 300, 70 moved_permanently = 301, 71 found = 302, 72 see_other = 303, 73 not_modified = 304, 74 moved_temporarily = 307, 75 bad_request = 400, 76 unauthorized = 401, 77 forbidden = 403, 78 not_found = 404, 79 request_entity_too_large = 413, 80 requested_range_not_satisfiable = 416, 81 internal_server_error = 500, 82 not_implemented = 501, 83 bad_gateway = 502, 84 service_unavailable = 503, 85 version_not_supported = 505 86 }; 87 88 enum ws_opcode { 89 continuation = 0x0, 90 text_frame = 0x1, 91 binary_frame = 0x2, 92 connection_close = 0x8, 93 ping = 0x9, 94 pong = 0xA, 95 }; 96 97 /* 98 * Called after writing data. 99 * 100 * In case the write was successful, this may call send() again if 101 * more data is immediately available. 102 */ 103 virtual void writeDone(bool success); 104 105 /* 106 * Returns true if ready to read more. 107 */ 108 virtual bool consumeData(const char *begin, 109 const char *end, 110 Request::State state) = 0; 111 112 /* 113 * Returns false on failure (should abort reading more) 114 */ 115 virtual bool consumeWebSocketMessage(ws_opcode opcode, 116 const char* begin, 117 const char* end, 118 Request::State state); 119 120 void setConnection(ConnectionPtr connection); 121 bool nextWrappedContentBuffers(std::vector<asio::const_buffer>& result); 122 bool nextBuffers(std::vector<asio::const_buffer>& result); 123 bool closeConnection() const; setCloseConnection()124 void setCloseConnection() { closeConnection_ = true; } 125 void detectDisconnect(const std::function<void()>& callback); 126 127 128 void addHeader(const std::string name, const std::string value); 129 130 void receive(); 131 void send(); 132 configuration()133 const Configuration& configuration() { return configuration_; } 134 135 virtual void logReply(Wt::WLogger& logger); 136 void setStatus(status_type status); status()137 status_type status() const { return status_; } 138 139 protected: 140 Request& request_; 141 const Configuration& configuration_; 142 143 virtual std::string contentType() = 0; 144 virtual std::string location(); 145 virtual ::int64_t contentLength() = 0; 146 147 /* 148 * Provides next data to send. Will be called after send() has been called. 149 * Returns whether this is the last data for this request. 150 */ 151 virtual bool nextContentBuffers(std::vector<asio::const_buffer>& result) 152 = 0; 153 154 void setRelay(ReplyPtr reply); relay()155 ReplyPtr relay() const { return relay_; } 156 157 static std::string httpDate(time_t t); 158 connection()159 ConnectionPtr connection() const { return connection_; } transmitting()160 bool transmitting() const { return transmitting_; } 161 asio::const_buffer buf(const std::string &s); 162 163 private: 164 165 std::vector<std::pair<std::string, std::string> > headers_; 166 167 ConnectionPtr connection_; 168 169 status_type status_; 170 bool transmitting_; 171 bool closeConnection_; 172 bool chunkedEncoding_; 173 bool gzipEncoding_; 174 175 ::int64_t contentSent_; 176 ::int64_t contentOriginalSize_; 177 178 ReplyPtr relay_; 179 180 Wt::WStringStream buf_; 181 Wt::WStringStream postBuf_; 182 // don't use vector; on resize the strings in bufs_ are copied, causing the 183 // pointers in the asio buffer lists to become invalid 184 std::list<std::string> bufs_; 185 186 187 bool encodeNextContentBuffer(std::vector<asio::const_buffer>& result, 188 int& originalSize, int& encodedSize); 189 #ifdef WTHTTP_WITH_ZLIB 190 void initGzip(); 191 bool gzipBusy_; 192 z_stream gzipStrm_; 193 #endif 194 }; 195 196 typedef std::shared_ptr<Reply> ReplyPtr; 197 198 } // namespace server 199 } // namespace http 200 201 #endif // HTTP_REPLY_HPP 202