1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
// Copyright Maarten L. Hekkelman, Radboud University 2008-2013.
// Copyright Maarten L. Hekkelman, 2014-2022
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
/// \file
/// definition of the zeep::http::reply class encapsulating a valid HTTP reply
#include <zeep/config.hpp>
#include <boost/asio/buffer.hpp>
#include <zeep/http/header.hpp>
#include <zeep/xml/document.hpp>
#include <zeep/json/element.hpp>
namespace zeep::http
{
/// Various predefined HTTP status codes
enum status_type
{
cont = 100,
ok = 200,
created = 201,
accepted = 202,
no_content = 204,
multiple_choices = 300,
moved_permanently = 301,
moved_temporarily = 302,
see_other = 303,
not_modified = 304,
bad_request = 400,
unauthorized = 401,
forbidden = 403,
not_found = 404,
method_not_allowed = 405,
proxy_authentication_required = 407,
internal_server_error = 500,
not_implemented = 501,
bad_gateway = 502,
service_unavailable = 503
};
/// Return the error string for the status_type
std::string get_status_text(status_type status);
/// Return the string describing the status_type in more detail
std::string get_status_description(status_type status);
/// \brief the class containing all to generate a HTTP reply
///
/// Create a HTTP reply, should be either HTTP 1.0 or 1.1
class reply
{
public:
using cookie_directive = header;
/// Create a reply, default is HTTP 1.0. Use 1.1 if you want to use keep alive e.g.
reply(status_type status = internal_server_error, std::tuple<int,int> version = { 1, 0 });
reply(status_type status, std::tuple<int,int> version,
std::vector<header>&& headers, std::string&& payload);
reply(const reply& rhs);
reply(reply &&rhs);
~reply();
reply& operator=(const reply &);
reply& operator=(reply &&);
void reset();
void set_version(int version_major, int version_minor);
void set_version(std::tuple<int,int> version)
{
set_version(std::get<0>(version), std::get<1>(version));
}
/// Add a header with name \a name and value \a value
void set_header(const std::string& name, const std::string& value);
/// \brief Return the value of the header with name \a name
std::string get_header(const std::string& name) const;
/// \brief Remove the header with name \a name from the list of headers
void remove_header(const std::string& name);
/// Set a cookie
void set_cookie(const char* name, const std::string& value, std::initializer_list<cookie_directive> directives = {});
/// \brief Set a header to delete the \a name cookie
void set_delete_cookie(const char* name);
/// Get a cookie
std::string get_cookie(const char* name) const;
std::string get_content_type() const
{
return get_header("Content-Type");
}
void set_content_type(const std::string& type) ///< Set the Content-Type header
{
set_header("Content-Type", type);
}
/// Set the content and the content-type header depending on the content of doc (might be xhtml)
void set_content(xml::document& doc);
/// Set the content and the content-type header to text/xml
void set_content(const xml::element& data);
/// Set the content and the content-type header based on JSON data
void set_content(const json::element& json);
/// Set the content and the content-type header
void set_content(const std::string& data, const std::string& contentType);
/// Set the content by copying \a data and the content-type header
void set_content(const char* data, size_t size, const std::string& contentType);
/// To send a stream of data, with unknown size (using chunked transfer).
/// reply takes ownership of \a data and deletes it when done.
void set_content(std::istream* data, const std::string& contentType);
/// return the content, only useful if the content was set with
/// some constant string data.
const std::string& get_content() const
{
return m_content;
}
/// return the content of the reply as an array of boost::asio::const_buffer objects
std::vector<boost::asio::const_buffer> to_buffers() const;
/// for istream data, if the returned buffer array is empty, the data is done
std::vector<boost::asio::const_buffer> data_to_buffers();
/// Create a standard reply based on a HTTP status code
static reply stock_reply(status_type inStatus);
static reply stock_reply(status_type inStatus, const std::string& info);
/// Create a standard redirect reply with the specified \a location
static reply redirect(const std::string& location);
static reply redirect(const std::string& location, status_type status);
void set_status(status_type status) { m_status = status; }
status_type get_status() const { return m_status; }
/// return the size of the reply, only correct if the reply is fully memory based (no streams)
size_t size() const;
/// \brief Return true if the content will be sent chunked encoded
bool get_chunked() const { return m_chunked; }
/// for debugging
friend std::ostream& operator<<(std::ostream& os, const reply& rep);
private:
friend class reply_parser;
status_type m_status;
int m_version_major, m_version_minor;
std::vector<header> m_headers;
std::istream* m_data;
std::vector<char> m_buffer;
std::string m_content;
bool m_chunked = false;
char m_size_buffer[8]; ///< to store the string with the size for chunked encoding
// this status line is only here to have a sensible location to store it
mutable std::string m_status_line;
};
}
|