1 /** 2 * Orthanc - A Lightweight, RESTful DICOM Store 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 4 * Department, University Hospital of Liege, Belgium 5 * Copyright (C) 2017-2021 Osimis S.A., Belgium 6 * 7 * This program is free software: you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public License 9 * as published by the Free Software Foundation, either version 3 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program. If not, see 19 * <http://www.gnu.org/licenses/>. 20 **/ 21 22 23 #pragma once 24 25 #include "../Enumerations.h" 26 #include "IHttpOutputStream.h" 27 #include "IHttpStreamAnswer.h" 28 29 #include <list> 30 #include <string> 31 #include <stdint.h> 32 #include <map> 33 #include <vector> 34 35 namespace Orthanc 36 { 37 class ORTHANC_PUBLIC HttpOutput : public boost::noncopyable 38 { 39 private: 40 typedef std::list< std::pair<std::string, std::string> > Header; 41 42 class StateMachine : public boost::noncopyable 43 { 44 public: 45 enum State 46 { 47 State_WritingHeader, 48 State_WritingBody, 49 State_WritingMultipart, 50 State_Done 51 }; 52 53 private: 54 IHttpOutputStream& stream_; 55 State state_; 56 57 HttpStatus status_; 58 bool hasContentLength_; 59 uint64_t contentLength_; 60 uint64_t contentPosition_; 61 bool keepAlive_; 62 std::list<std::string> headers_; 63 64 std::string multipartBoundary_; 65 std::string multipartContentType_; 66 67 public: 68 StateMachine(IHttpOutputStream& stream, 69 bool isKeepAlive); 70 71 ~StateMachine(); 72 73 void SetHttpStatus(HttpStatus status); 74 75 void SetContentLength(uint64_t length); 76 77 void SetContentType(const char* contentType); 78 79 void SetContentFilename(const char* filename); 80 81 void SetCookie(const std::string& cookie, 82 const std::string& value); 83 84 void AddHeader(const std::string& header, 85 const std::string& value); 86 87 void ClearHeaders(); 88 89 void SendBody(const void* buffer, size_t length); 90 91 void StartMultipart(const std::string& subType, 92 const std::string& contentType); 93 94 void SendMultipartItem(const void* item, 95 size_t length, 96 const std::map<std::string, std::string>& headers); 97 98 void CloseMultipart(); 99 100 void CloseBody(); 101 GetState()102 State GetState() const 103 { 104 return state_; 105 } 106 107 void CheckHeadersCompatibilityWithMultipart() const; 108 }; 109 110 StateMachine stateMachine_; 111 bool isDeflateAllowed_; 112 bool isGzipAllowed_; 113 114 HttpCompression GetPreferredCompression(size_t bodySize) const; 115 116 public: 117 HttpOutput(IHttpOutputStream& stream, 118 bool isKeepAlive); 119 120 void SetDeflateAllowed(bool allowed); 121 122 bool IsDeflateAllowed() const; 123 124 void SetGzipAllowed(bool allowed); 125 126 bool IsGzipAllowed() const; 127 128 void SendStatus(HttpStatus status, 129 const char* message, 130 size_t messageSize); 131 132 void SendStatus(HttpStatus status); 133 134 void SendStatus(HttpStatus status, 135 const std::string& message); 136 137 void SetContentType(MimeType contentType); 138 139 void SetContentType(const std::string& contentType); 140 141 void SetContentFilename(const char* filename); 142 143 void SetCookie(const std::string& cookie, 144 const std::string& value); 145 146 void AddHeader(const std::string& key, 147 const std::string& value); 148 149 void Answer(const void* buffer, 150 size_t length); 151 152 void Answer(const std::string& str); 153 154 void AnswerEmpty(); 155 156 void SendMethodNotAllowed(const std::string& allowed); 157 158 void Redirect(const std::string& path); 159 160 void SendUnauthorized(const std::string& realm); 161 162 void StartMultipart(const std::string& subType, 163 const std::string& contentType); 164 165 void SendMultipartItem(const void* item, 166 size_t size, 167 const std::map<std::string, std::string>& headers); 168 169 void CloseMultipart(); 170 171 bool IsWritingMultipart() const; 172 173 void Answer(IHttpStreamAnswer& stream); 174 175 /** 176 * This method is a replacement to the combination 177 * "StartMultipart()" + "SendMultipartItem()". It generates the 178 * same answer, but it gives a chance to compress the body if 179 * "Accept-Encoding: gzip" is provided by the client, which is not 180 * possible in chunked transfers. 181 **/ 182 void AnswerMultipartWithoutChunkedTransfer( 183 const std::string& subType, 184 const std::string& contentType, 185 const std::vector<const void*>& parts, 186 const std::vector<size_t>& sizes, 187 const std::vector<const std::map<std::string, std::string>*>& headers); 188 }; 189 } 190