Mercurial > hg > orthanc
annotate OrthancFramework/Sources/HttpServer/HttpOutput.cpp @ 5839:7aef730c0859 default tip
cont
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 16 Oct 2024 19:34:42 +0200 |
parents | f7adfb22e20e |
children |
rev | line source |
---|---|
0 | 1 /** |
59 | 2 * Orthanc - A Lightweight, RESTful DICOM Store |
1900 | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
1288
6e7e5ed91c2d
upgrade to year 2015
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1200
diff
changeset
|
4 * Department, University Hospital of Liege, Belgium |
5640
f7adfb22e20e
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5584
diff
changeset
|
5 * Copyright (C) 2017-2023 Osimis S.A., Belgium |
f7adfb22e20e
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5584
diff
changeset
|
6 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium |
5485
48b8dae6dc77
upgrade to year 2024
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5469
diff
changeset
|
7 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
0 | 8 * |
9 * This program is free software: you can redistribute it and/or | |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
10 * modify it under the terms of the GNU Lesser General Public License |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
11 * as published by the Free Software Foundation, either version 3 of |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
12 * the License, or (at your option) any later version. |
136 | 13 * |
0 | 14 * This program is distributed in the hope that it will be useful, but |
15 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
17 * Lesser General Public License for more details. |
0 | 18 * |
4119
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
19 * You should have received a copy of the GNU Lesser General Public |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
20 * License along with this program. If not, see |
bf7b9edf6b81
re-licensing the OrthancFramework to LGPL, in order to license Stone of Orthanc under LGPL
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4044
diff
changeset
|
21 * <http://www.gnu.org/licenses/>. |
0 | 22 **/ |
23 | |
24 | |
824
a811bdf8b8eb
precompiled headers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
25 #include "../PrecompiledHeaders.h" |
0 | 26 #include "HttpOutput.h" |
27 | |
3380
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
28 #include "../ChunkedBuffer.h" |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
29 #include "../Compression/GzipCompressor.h" |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
30 #include "../Compression/ZlibCompressor.h" |
1486
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1430
diff
changeset
|
31 #include "../Logging.h" |
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1430
diff
changeset
|
32 #include "../OrthancException.h" |
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1430
diff
changeset
|
33 #include "../Toolbox.h" |
5407
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
34 #include "../SystemToolbox.h" |
1486
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1430
diff
changeset
|
35 |
324 | 36 #include <iostream> |
0 | 37 #include <vector> |
38 #include <stdio.h> | |
39 #include <boost/lexical_cast.hpp> | |
1486
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1430
diff
changeset
|
40 |
0 | 41 |
3178
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
42 #if ORTHANC_ENABLE_CIVETWEB == 1 |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
43 # if !defined(CIVETWEB_HAS_DISABLE_KEEP_ALIVE) |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
44 # error Macro CIVETWEB_HAS_DISABLE_KEEP_ALIVE must be defined |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
45 # endif |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
46 #endif |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
47 |
5469
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
48 static const std::string X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options"; |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
49 |
3178
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
50 |
59 | 51 namespace Orthanc |
0 | 52 { |
1115
da56a7916e8a
Experimental "KeepAlive" configuration option to enable HTTP Keep-Alive
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1113
diff
changeset
|
53 HttpOutput::StateMachine::StateMachine(IHttpOutputStream& stream, |
5119
bdec57f3cbf2
New configuration KeepAliveTimeout with a default value of 1 second
Alain Mazy <am@osimis.io>
parents:
4870
diff
changeset
|
54 bool isKeepAlive, |
bdec57f3cbf2
New configuration KeepAliveTimeout with a default value of 1 second
Alain Mazy <am@osimis.io>
parents:
4870
diff
changeset
|
55 unsigned int keepAliveTimeout) : |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
56 stream_(stream), |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
57 state_(State_WritingHeader), |
5407
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
58 isContentCompressible_(false), |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
59 status_(HttpStatus_200_Ok), |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
60 hasContentLength_(false), |
4201 | 61 contentLength_(0), |
1115
da56a7916e8a
Experimental "KeepAlive" configuration option to enable HTTP Keep-Alive
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1113
diff
changeset
|
62 contentPosition_(0), |
5119
bdec57f3cbf2
New configuration KeepAliveTimeout with a default value of 1 second
Alain Mazy <am@osimis.io>
parents:
4870
diff
changeset
|
63 keepAlive_(isKeepAlive), |
5469
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
64 keepAliveTimeout_(keepAliveTimeout), |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
65 hasXContentTypeOptions_(false) |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
66 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
67 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
68 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
69 HttpOutput::StateMachine::~StateMachine() |
910 | 70 { |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
71 if (state_ != State_Done) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
72 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
73 //asm volatile ("int3;"); |
1200 | 74 //LOG(ERROR) << "This HTTP answer does not contain any body"; |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
75 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
76 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
77 if (hasContentLength_ && contentPosition_ != contentLength_) |
910 | 78 { |
5547 | 79 LOG(ERROR) << "This HTTP answer has not sent the proper number of bytes in its body. The remote client has likely closed the connection."; |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
80 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
81 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
82 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
83 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
84 void HttpOutput::StateMachine::SetHttpStatus(HttpStatus status) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
85 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
86 if (state_ != State_WritingHeader) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
87 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
88 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
910 | 89 } |
90 | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
91 status_ = status; |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
92 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
93 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
94 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
95 void HttpOutput::StateMachine::SetContentLength(uint64_t length) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
96 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
97 if (state_ != State_WritingHeader) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
98 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
99 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
100 } |
910 | 101 |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
102 hasContentLength_ = true; |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
103 contentLength_ = length; |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
104 } |
910 | 105 |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
106 void HttpOutput::StateMachine::SetContentType(const char* contentType) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
107 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
108 AddHeader("Content-Type", contentType); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
109 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
110 |
5407
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
111 void HttpOutput::StateMachine::SetContentCompressible(bool isContentCompressible) |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
112 { |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
113 isContentCompressible_ = isContentCompressible; |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
114 } |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
115 |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
116 bool HttpOutput::StateMachine::IsContentCompressible() const |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
117 { |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
118 // We assume that all files that compress correctly (mainly JSON, XML) are clearly identified. |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
119 return isContentCompressible_; |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
120 } |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
121 |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
122 void HttpOutput::StateMachine::SetContentFilename(const char* filename) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
123 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
124 // TODO Escape double quotes |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
125 AddHeader("Content-Disposition", "filename=\"" + std::string(filename) + "\""); |
910 | 126 } |
127 | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
128 void HttpOutput::StateMachine::SetCookie(const std::string& cookie, |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
129 const std::string& value) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
130 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
131 if (state_ != State_WritingHeader) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
132 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
133 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
134 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
135 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
136 // TODO Escape "=" characters |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
137 AddHeader("Set-Cookie", cookie + "=" + value); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
138 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
139 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
140 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
141 void HttpOutput::StateMachine::AddHeader(const std::string& header, |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
142 const std::string& value) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
143 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
144 if (state_ != State_WritingHeader) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
145 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
146 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
147 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
148 |
5469
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
149 if (header == X_CONTENT_TYPE_OPTIONS) |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
150 { |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
151 hasXContentTypeOptions_ = true; |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
152 } |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
153 |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
154 headers_.push_back(header + ": " + value + "\r\n"); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
155 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
156 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
157 void HttpOutput::StateMachine::ClearHeaders() |
910 | 158 { |
159 if (state_ != State_WritingHeader) | |
160 { | |
161 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
162 } | |
163 | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
164 headers_.clear(); |
910 | 165 } |
166 | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
167 void HttpOutput::StateMachine::SendBody(const void* buffer, size_t length) |
910 | 168 { |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
169 if (state_ == State_Done) |
910 | 170 { |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
171 if (length == 0) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
172 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
173 return; |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
174 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
175 else |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
176 { |
2954
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
177 throw OrthancException(ErrorCode_BadSequenceOfCalls, |
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
178 "Because of keep-alive connections, the entire body must " |
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
179 "be sent at once or Content-Length must be given"); |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
180 } |
910 | 181 } |
182 | |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
183 if (state_ == State_WritingMultipart) |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
184 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
185 throw OrthancException(ErrorCode_InternalError); |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
186 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
187 |
910 | 188 if (state_ == State_WritingHeader) |
189 { | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
190 // Send the HTTP header before writing the body |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
191 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
192 stream_.OnHttpStatusReceived(status_); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
193 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
194 std::string s = "HTTP/1.1 " + |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
195 boost::lexical_cast<std::string>(status_) + |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
196 " " + std::string(EnumerationToString(status_)) + |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
197 "\r\n"; |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
198 |
1115
da56a7916e8a
Experimental "KeepAlive" configuration option to enable HTTP Keep-Alive
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1113
diff
changeset
|
199 if (keepAlive_) |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
200 { |
1115
da56a7916e8a
Experimental "KeepAlive" configuration option to enable HTTP Keep-Alive
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1113
diff
changeset
|
201 s += "Connection: keep-alive\r\n"; |
4301
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
202 |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
203 /** |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
204 * [LIFY-2311] The "Keep-Alive" HTTP header was missing in |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
205 * Orthanc <= 1.8.0, which notably caused failures if |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
206 * uploading DICOM instances by applying Java's |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
207 * "org.apache.http.client.methods.HttpPost()" on "/instances" |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
208 * URI, if "PoolingHttpClientConnectionManager" was in used. A |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
209 * workaround was to manually set a timeout for the keep-alive |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
210 * client to, say, 200 milliseconds, by using |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
211 * "HttpClients.custom().setKeepAliveStrategy((httpResponse,httpContext)->200)". |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
212 * Note that the "timeout" value can only be integer in the |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
213 * HTTP header, so we can't use the milliseconds granularity. |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
214 **/ |
6919242d2265
Fix keep-alive in the embedded HTTP server by setting the "Keep-Alive" HTTP header
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4298
diff
changeset
|
215 s += ("Keep-Alive: timeout=" + |
5119
bdec57f3cbf2
New configuration KeepAliveTimeout with a default value of 1 second
Alain Mazy <am@osimis.io>
parents:
4870
diff
changeset
|
216 boost::lexical_cast<std::string>(keepAliveTimeout_) + "\r\n"); |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
217 } |
3171
81cd9a4f3018
always add HTTP header "Connection: close" if keep-alive is disabled
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3154
diff
changeset
|
218 else |
81cd9a4f3018
always add HTTP header "Connection: close" if keep-alive is disabled
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3154
diff
changeset
|
219 { |
81cd9a4f3018
always add HTTP header "Connection: close" if keep-alive is disabled
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3154
diff
changeset
|
220 s += "Connection: close\r\n"; |
81cd9a4f3018
always add HTTP header "Connection: close" if keep-alive is disabled
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3154
diff
changeset
|
221 } |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
222 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
223 for (std::list<std::string>::const_iterator |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
224 it = headers_.begin(); it != headers_.end(); ++it) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
225 { |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
226 s += *it; |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
227 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
228 |
5469
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
229 if (!hasXContentTypeOptions_) |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
230 { |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
231 // Always include this header to prevent MIME Confusion attacks: |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
232 // https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-content-type-options |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
233 s += X_CONTENT_TYPE_OPTIONS + ": nosniff\r\n"; |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
234 } |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
235 |
1115
da56a7916e8a
Experimental "KeepAlive" configuration option to enable HTTP Keep-Alive
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1113
diff
changeset
|
236 if (status_ != HttpStatus_200_Ok) |
da56a7916e8a
Experimental "KeepAlive" configuration option to enable HTTP Keep-Alive
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1113
diff
changeset
|
237 { |
da56a7916e8a
Experimental "KeepAlive" configuration option to enable HTTP Keep-Alive
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1113
diff
changeset
|
238 hasContentLength_ = false; |
da56a7916e8a
Experimental "KeepAlive" configuration option to enable HTTP Keep-Alive
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1113
diff
changeset
|
239 } |
da56a7916e8a
Experimental "KeepAlive" configuration option to enable HTTP Keep-Alive
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1113
diff
changeset
|
240 |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
241 uint64_t contentLength = (hasContentLength_ ? contentLength_ : length); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
242 s += "Content-Length: " + boost::lexical_cast<std::string>(contentLength) + "\r\n\r\n"; |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
243 |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
244 stream_.Send(true, s.c_str(), s.size()); |
910 | 245 state_ = State_WritingBody; |
246 } | |
247 | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
248 if (hasContentLength_ && |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
249 contentPosition_ + length > contentLength_) |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
250 { |
2954
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
251 throw OrthancException(ErrorCode_BadSequenceOfCalls, |
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
252 "The body size exceeds what was declared with SetContentSize()"); |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
253 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
254 |
910 | 255 if (length > 0) |
256 { | |
911 | 257 stream_.Send(false, buffer, length); |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
258 contentPosition_ += length; |
330 | 259 } |
260 | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
261 if (!hasContentLength_ || |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
262 contentPosition_ == contentLength_) |
330 | 263 { |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
264 state_ = State_Done; |
330 | 265 } |
266 } | |
267 | |
207 | 268 |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
269 void HttpOutput::StateMachine::CloseBody() |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
270 { |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
271 switch (state_) |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
272 { |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
273 case State_WritingHeader: |
1522 | 274 SetContentLength(0); |
275 SendBody(NULL, 0); | |
276 break; | |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
277 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
278 case State_WritingBody: |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
279 if (!hasContentLength_ || |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
280 contentPosition_ == contentLength_) |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
281 { |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
282 state_ = State_Done; |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
283 } |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
284 else |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
285 { |
2954
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
286 throw OrthancException(ErrorCode_BadSequenceOfCalls, |
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
287 "The body size has not reached what was declared with SetContentSize()"); |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
288 } |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
289 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
290 break; |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
291 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
292 case State_WritingMultipart: |
2954
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
293 throw OrthancException(ErrorCode_BadSequenceOfCalls, |
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
294 "Cannot invoke CloseBody() with multipart outputs"); |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
295 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
296 case State_Done: |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
297 return; // Ignore |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
298 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
299 default: |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
300 throw OrthancException(ErrorCode_InternalError); |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
301 } |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
302 } |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
303 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
304 |
1517 | 305 HttpCompression HttpOutput::GetPreferredCompression(size_t bodySize) const |
306 { | |
5407
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
307 // Do not compress small files since there is no real size benefit. |
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
308 if (bodySize < 2048) |
1517 | 309 { |
310 return HttpCompression_None; | |
311 } | |
312 | |
313 // Prefer "gzip" over "deflate" if the choice is offered | |
314 | |
315 if (isGzipAllowed_) | |
316 { | |
317 return HttpCompression_Gzip; | |
318 } | |
319 else if (isDeflateAllowed_) | |
320 { | |
321 return HttpCompression_Deflate; | |
322 } | |
323 else | |
324 { | |
325 return HttpCompression_None; | |
326 } | |
327 } | |
328 | |
329 | |
4298 | 330 HttpOutput::HttpOutput(IHttpOutputStream &stream, |
5119
bdec57f3cbf2
New configuration KeepAliveTimeout with a default value of 1 second
Alain Mazy <am@osimis.io>
parents:
4870
diff
changeset
|
331 bool isKeepAlive, |
bdec57f3cbf2
New configuration KeepAliveTimeout with a default value of 1 second
Alain Mazy <am@osimis.io>
parents:
4870
diff
changeset
|
332 unsigned int keepAliveTimeout) : |
bdec57f3cbf2
New configuration KeepAliveTimeout with a default value of 1 second
Alain Mazy <am@osimis.io>
parents:
4870
diff
changeset
|
333 stateMachine_(stream, isKeepAlive, keepAliveTimeout), |
4298 | 334 isDeflateAllowed_(false), |
335 isGzipAllowed_(false) | |
336 { | |
337 } | |
338 | |
339 void HttpOutput::SetDeflateAllowed(bool allowed) | |
340 { | |
341 isDeflateAllowed_ = allowed; | |
342 } | |
343 | |
344 bool HttpOutput::IsDeflateAllowed() const | |
345 { | |
346 return isDeflateAllowed_; | |
347 } | |
348 | |
349 void HttpOutput::SetGzipAllowed(bool allowed) | |
350 { | |
351 isGzipAllowed_ = allowed; | |
352 } | |
353 | |
354 bool HttpOutput::IsGzipAllowed() const | |
355 { | |
356 return isGzipAllowed_; | |
357 } | |
358 | |
359 | |
1042
8d1845feb277
set cookies, not allowed methods, unauthorized in plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
911
diff
changeset
|
360 void HttpOutput::SendMethodNotAllowed(const std::string& allowed) |
0 | 361 { |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
362 stateMachine_.ClearHeaders(); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
363 stateMachine_.SetHttpStatus(HttpStatus_405_MethodNotAllowed); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
364 stateMachine_.AddHeader("Allow", allowed); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
365 stateMachine_.SendBody(NULL, 0); |
0 | 366 } |
367 | |
368 | |
1567
9c5d93510414
If error while calling the REST API, the answer body contains an error description
jodogne
parents:
1523
diff
changeset
|
369 void HttpOutput::SendStatus(HttpStatus status, |
5462
505416b269a0
Fix XSS in Orthanc error reporting (as reported by Sébastien Doria, Vumetric Cybersecurity)
Alain Mazy <am@osimis.io>
parents:
5432
diff
changeset
|
370 const char* message, |
505416b269a0
Fix XSS in Orthanc error reporting (as reported by Sébastien Doria, Vumetric Cybersecurity)
Alain Mazy <am@osimis.io>
parents:
5432
diff
changeset
|
371 size_t messageSize) |
0 | 372 { |
1954 | 373 if (status == HttpStatus_301_MovedPermanently || |
3425 | 374 //status == HttpStatus_401_Unauthorized || |
473
c9a5d72f8481
changing the namespace of HTTP enumerations
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
398
diff
changeset
|
375 status == HttpStatus_405_MethodNotAllowed) |
0 | 376 { |
2954
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
377 throw OrthancException(ErrorCode_ParameterOutOfRange, |
d924f9bb61cc
taking advantage of details in OrthancException
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2908
diff
changeset
|
378 "Please use the dedicated methods to this HTTP status code in HttpOutput"); |
0 | 379 } |
380 | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
381 stateMachine_.SetHttpStatus(status); |
5462
505416b269a0
Fix XSS in Orthanc error reporting (as reported by Sébastien Doria, Vumetric Cybersecurity)
Alain Mazy <am@osimis.io>
parents:
5432
diff
changeset
|
382 |
505416b269a0
Fix XSS in Orthanc error reporting (as reported by Sébastien Doria, Vumetric Cybersecurity)
Alain Mazy <am@osimis.io>
parents:
5432
diff
changeset
|
383 if (messageSize > 0) |
505416b269a0
Fix XSS in Orthanc error reporting (as reported by Sébastien Doria, Vumetric Cybersecurity)
Alain Mazy <am@osimis.io>
parents:
5432
diff
changeset
|
384 { |
5469
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
385 // Assume that the body always contains a textual description of the error |
514fd39f87a8
improved handling of X-Content-Type-Options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5463
diff
changeset
|
386 stateMachine_.SetContentType("text/plain"); |
5462
505416b269a0
Fix XSS in Orthanc error reporting (as reported by Sébastien Doria, Vumetric Cybersecurity)
Alain Mazy <am@osimis.io>
parents:
5432
diff
changeset
|
387 } |
505416b269a0
Fix XSS in Orthanc error reporting (as reported by Sébastien Doria, Vumetric Cybersecurity)
Alain Mazy <am@osimis.io>
parents:
5432
diff
changeset
|
388 |
1645
1558b3226b18
IHttpExceptionFormatter
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1592
diff
changeset
|
389 stateMachine_.SendBody(message, messageSize); |
339 | 390 } |
391 | |
4298 | 392 void HttpOutput::SendStatus(HttpStatus status) |
393 { | |
394 SendStatus(status, NULL, 0); | |
395 } | |
396 | |
397 void HttpOutput::SendStatus(HttpStatus status, const std::string &message) | |
398 { | |
399 SendStatus(status, message.c_str(), message.size()); | |
400 } | |
401 | |
402 void HttpOutput::SetContentType(MimeType contentType) | |
403 { | |
404 stateMachine_.SetContentType(EnumerationToString(contentType)); | |
5407
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
405 stateMachine_.SetContentCompressible(SystemToolbox::IsContentCompressible(contentType)); |
4298 | 406 } |
407 | |
408 void HttpOutput::SetContentType(const std::string &contentType) | |
409 { | |
410 stateMachine_.SetContentType(contentType.c_str()); | |
5407
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
411 stateMachine_.SetContentCompressible(SystemToolbox::IsContentCompressible(contentType)); |
4298 | 412 } |
413 | |
414 void HttpOutput::SetContentFilename(const char *filename) | |
415 { | |
416 stateMachine_.SetContentFilename(filename); | |
417 } | |
418 | |
419 void HttpOutput::SetCookie(const std::string &cookie, const std::string &value) | |
420 { | |
421 stateMachine_.SetCookie(cookie, value); | |
422 } | |
423 | |
424 void HttpOutput::AddHeader(const std::string &key, const std::string &value) | |
425 { | |
426 stateMachine_.AddHeader(key, value); | |
427 } | |
428 | |
339 | 429 |
0 | 430 void HttpOutput::Redirect(const std::string& path) |
431 { | |
5584
1b31ab38ea94
using HttpStatus_307_TemporaryRedirect for redirections
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5547
diff
changeset
|
432 /** |
1b31ab38ea94
using HttpStatus_307_TemporaryRedirect for redirections
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5547
diff
changeset
|
433 * "HttpStatus_301_MovedPermanently" was used in Orthanc <= |
1b31ab38ea94
using HttpStatus_307_TemporaryRedirect for redirections
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5547
diff
changeset
|
434 * 1.12.3. This caused issues on changes in the configuration of |
1b31ab38ea94
using HttpStatus_307_TemporaryRedirect for redirections
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5547
diff
changeset
|
435 * Orthanc. |
1b31ab38ea94
using HttpStatus_307_TemporaryRedirect for redirections
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5547
diff
changeset
|
436 **/ |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
437 stateMachine_.ClearHeaders(); |
5584
1b31ab38ea94
using HttpStatus_307_TemporaryRedirect for redirections
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5547
diff
changeset
|
438 stateMachine_.SetHttpStatus(HttpStatus_307_TemporaryRedirect); |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
439 stateMachine_.AddHeader("Location", path); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
440 stateMachine_.SendBody(NULL, 0); |
0 | 441 } |
908
e078ea944089
refactoring HttpOutput
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
824
diff
changeset
|
442 |
e078ea944089
refactoring HttpOutput
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
824
diff
changeset
|
443 |
e078ea944089
refactoring HttpOutput
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
824
diff
changeset
|
444 void HttpOutput::SendUnauthorized(const std::string& realm) |
e078ea944089
refactoring HttpOutput
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
824
diff
changeset
|
445 { |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
446 stateMachine_.ClearHeaders(); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
447 stateMachine_.SetHttpStatus(HttpStatus_401_Unauthorized); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
448 stateMachine_.AddHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\""); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
449 stateMachine_.SendBody(NULL, 0); |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
450 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
451 |
4298 | 452 void HttpOutput::StartMultipart(const std::string &subType, const std::string &contentType) |
453 { | |
454 stateMachine_.StartMultipart(subType, contentType); | |
455 } | |
456 | |
457 void HttpOutput::SendMultipartItem(const void *item, | |
458 size_t size, | |
459 const std::map<std::string, std::string> &headers) | |
460 { | |
461 stateMachine_.SendMultipartItem(item, size, headers); | |
462 } | |
463 | |
464 void HttpOutput::CloseMultipart() | |
465 { | |
466 stateMachine_.CloseMultipart(); | |
467 } | |
468 | |
469 bool HttpOutput::IsWritingMultipart() const | |
470 { | |
471 return stateMachine_.GetState() == StateMachine::State_WritingMultipart; | |
472 } | |
473 | |
2908
9d277f8ad698
new enumeration: MimeType
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2905
diff
changeset
|
474 |
4298 | 475 void HttpOutput::Answer(const void* buffer, |
1521 | 476 size_t length) |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
477 { |
1511
7962563129c9
starting support of deflate/gzip content types
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1486
diff
changeset
|
478 if (length == 0) |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
479 { |
1521 | 480 AnswerEmpty(); |
481 return; | |
482 } | |
483 | |
484 HttpCompression compression = GetPreferredCompression(length); | |
485 | |
5407
3206537cbb56
HttpCompression: now disabled by default + only compress known compressible content types
Alain Mazy <am@osimis.io>
parents:
5185
diff
changeset
|
486 if (compression == HttpCompression_None || !IsContentCompressible()) |
1521 | 487 { |
488 stateMachine_.SetContentLength(length); | |
489 stateMachine_.SendBody(buffer, length); | |
490 return; | |
491 } | |
492 | |
493 std::string compressed, encoding; | |
494 | |
495 switch (compression) | |
496 { | |
497 case HttpCompression_Deflate: | |
498 { | |
499 encoding = "deflate"; | |
500 ZlibCompressor compressor; | |
501 // Do not prefix the buffer with its uncompressed size, to be compatible with "deflate" | |
502 compressor.SetPrefixWithUncompressedSize(false); | |
503 compressor.Compress(compressed, buffer, length); | |
504 break; | |
505 } | |
506 | |
507 case HttpCompression_Gzip: | |
508 { | |
509 encoding = "gzip"; | |
510 GzipCompressor compressor; | |
511 compressor.Compress(compressed, buffer, length); | |
512 break; | |
513 } | |
514 | |
515 default: | |
516 throw OrthancException(ErrorCode_InternalError); | |
517 } | |
518 | |
519 LOG(TRACE) << "Compressing a HTTP answer using " << encoding; | |
520 | |
521 // The body is empty, do not use HTTP compression | |
522 if (compressed.size() == 0) | |
523 { | |
524 AnswerEmpty(); | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
525 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
526 else |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
527 { |
1521 | 528 stateMachine_.AddHeader("Content-Encoding", encoding); |
529 stateMachine_.SetContentLength(compressed.size()); | |
530 stateMachine_.SendBody(compressed.c_str(), compressed.size()); | |
531 } | |
1511
7962563129c9
starting support of deflate/gzip content types
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1486
diff
changeset
|
532 |
1521 | 533 stateMachine_.CloseBody(); |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
534 } |
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
535 |
1521 | 536 |
537 void HttpOutput::Answer(const std::string& str) | |
1511
7962563129c9
starting support of deflate/gzip content types
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1486
diff
changeset
|
538 { |
1521 | 539 Answer(str.size() == 0 ? NULL : str.c_str(), str.size()); |
1511
7962563129c9
starting support of deflate/gzip content types
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1486
diff
changeset
|
540 } |
7962563129c9
starting support of deflate/gzip content types
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1486
diff
changeset
|
541 |
1521 | 542 |
543 void HttpOutput::AnswerEmpty() | |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
544 { |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
545 stateMachine_.CloseBody(); |
1113
ba5c0908600c
Refactoring of HttpOutput ("Content-Length" header is now always sent)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1042
diff
changeset
|
546 } |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
547 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
548 |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
549 void HttpOutput::StateMachine::CheckHeadersCompatibilityWithMultipart() const |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
550 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
551 for (std::list<std::string>::const_iterator |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
552 it = headers_.begin(); it != headers_.end(); ++it) |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
553 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
554 if (!Toolbox::StartsWith(*it, "Set-Cookie: ")) |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
555 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
556 throw OrthancException(ErrorCode_BadSequenceOfCalls, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
557 "The only headers that can be set in multipart answers " |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
558 "are Set-Cookie (here: " + *it + " is set)"); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
559 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
560 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
561 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
562 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
563 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
564 static void PrepareMultipartMainHeader(std::string& boundary, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
565 std::string& contentTypeHeader, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
566 const std::string& subType, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
567 const std::string& contentType) |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
568 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
569 if (subType != "mixed" && |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
570 subType != "related") |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
571 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
572 throw OrthancException(ErrorCode_ParameterOutOfRange); |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
573 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
574 |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
575 /** |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
576 * Fix for issue 54 ("Decide what to do wrt. quoting of multipart |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
577 * answers"). The "type" parameter in the "Content-Type" HTTP |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
578 * header must be quoted if it contains a forward slash "/". This |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
579 * is necessary for DICOMweb compatibility with OsiriX, but breaks |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
580 * compatibility with old releases of the client in the Orthanc |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
581 * DICOMweb plugin <= 0.3 (releases >= 0.4 work fine). |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
582 * |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
583 * Full history is available at the following locations: |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
584 * - In changeset 2248:69b0f4e8a49b: |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
585 * # hg history -v -r 2248 |
5432
59e3b6f8c5be
migration to UCLouvain servers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5407
diff
changeset
|
586 * - https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=54 |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
587 * - https://groups.google.com/d/msg/orthanc-users/65zhIM5xbKI/TU5Q1_LhAwAJ |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
588 **/ |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
589 std::string tmp; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
590 if (contentType.find('/') == std::string::npos) |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
591 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
592 // No forward slash in the content type |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
593 tmp = contentType; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
594 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
595 else |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
596 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
597 // Quote the content type because of the forward slash |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
598 tmp = "\"" + contentType + "\""; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
599 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
600 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
601 boundary = Toolbox::GenerateUuid() + "-" + Toolbox::GenerateUuid(); |
3616 | 602 |
603 /** | |
604 * Fix for issue #165: "Encapsulation boundaries must not appear | |
605 * within the encapsulations, and must be no longer than 70 | |
606 * characters, not counting the two leading hyphens." | |
607 * https://tools.ietf.org/html/rfc1521 | |
5432
59e3b6f8c5be
migration to UCLouvain servers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
5407
diff
changeset
|
608 * https://orthanc.uclouvain.be/bugs/show_bug.cgi?id=165 |
3616 | 609 **/ |
610 if (boundary.size() != 36 + 1 + 36) // one UUID contains 36 characters | |
611 { | |
612 throw OrthancException(ErrorCode_InternalError); | |
613 } | |
614 | |
615 boundary = boundary.substr(0, 70); | |
616 | |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
617 contentTypeHeader = ("multipart/" + subType + "; type=" + tmp + "; boundary=" + boundary); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
618 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
619 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
620 |
4672
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
621 void HttpOutput::StateMachine::StartStreamInternal(const std::string& contentType) |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
622 { |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
623 if (state_ != State_WritingHeader) |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
624 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
625 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
626 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
627 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
628 if (status_ != HttpStatus_200_Ok) |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
629 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
630 SendBody(NULL, 0); |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
631 return; |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
632 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
633 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
634 stream_.OnHttpStatusReceived(status_); |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
635 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
636 std::string header = "HTTP/1.1 200 OK\r\n"; |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
637 |
3154
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
638 if (keepAlive_) |
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
639 { |
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
640 #if ORTHANC_ENABLE_MONGOOSE == 1 |
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
641 throw OrthancException(ErrorCode_NotImplemented, |
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
642 "Multipart answers are not implemented together " |
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
643 "with keep-alive connections if using Mongoose"); |
3178
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
644 |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
645 #elif ORTHANC_ENABLE_CIVETWEB == 1 |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
646 # if CIVETWEB_HAS_DISABLE_KEEP_ALIVE == 1 |
3154
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
647 // Turn off Keep-Alive for multipart answers |
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
648 // https://github.com/civetweb/civetweb/issues/727 |
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
649 stream_.DisableKeepAlive(); |
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
650 header += "Connection: close\r\n"; |
3178
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
651 # else |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
652 // The function "mg_disable_keep_alive()" is not available, |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
653 // let's continue with Keep-Alive. Performance of WADO-RS will |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
654 // decrease. |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
655 header += "Connection: keep-alive\r\n"; |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
656 # endif |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
657 |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
658 #else |
6d558598d713
Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()")
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3171
diff
changeset
|
659 # error Please support your embedded Web server here |
3154
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
660 #endif |
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
661 } |
3171
81cd9a4f3018
always add HTTP header "Connection: close" if keep-alive is disabled
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3154
diff
changeset
|
662 else |
81cd9a4f3018
always add HTTP header "Connection: close" if keep-alive is disabled
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3154
diff
changeset
|
663 { |
81cd9a4f3018
always add HTTP header "Connection: close" if keep-alive is disabled
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3154
diff
changeset
|
664 header += "Connection: close\r\n"; |
81cd9a4f3018
always add HTTP header "Connection: close" if keep-alive is disabled
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3154
diff
changeset
|
665 } |
3154
6e8822be2f08
Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
666 |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
667 for (std::list<std::string>::const_iterator |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
668 it = headers_.begin(); it != headers_.end(); ++it) |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
669 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
670 header += *it; |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
671 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
672 |
4672
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
673 header += ("Content-Type: " + contentType + "\r\n\r\n"); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
674 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
675 stream_.Send(true, header.c_str(), header.size()); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
676 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
677 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
678 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
679 void HttpOutput::StateMachine::StartMultipart(const std::string& subType, |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
680 const std::string& contentType) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
681 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
682 CheckHeadersCompatibilityWithMultipart(); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
683 |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
684 std::string contentTypeHeader; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
685 PrepareMultipartMainHeader(multipartBoundary_, contentTypeHeader, subType, contentType); |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
686 multipartContentType_ = contentType; |
4672
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
687 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
688 StartStreamInternal(contentTypeHeader); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
689 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
690 state_ = State_WritingMultipart; |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
691 } |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
692 |
4672
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
693 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
694 void HttpOutput::StateMachine::StartStream(const std::string& contentType) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
695 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
696 StartStreamInternal(contentType); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
697 state_ = State_WritingStream; |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
698 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
699 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
700 |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
701 static void PrepareMultipartItemHeader(std::string& target, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
702 size_t length, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
703 const std::map<std::string, std::string>& headers, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
704 const std::string& boundary, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
705 const std::string& contentType) |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
706 { |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
707 target = "--" + boundary + "\r\n"; |
1882
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
708 |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
709 bool hasContentType = false; |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
710 bool hasContentLength = false; |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
711 bool hasMimeVersion = false; |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
712 |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
713 for (std::map<std::string, std::string>::const_iterator |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
714 it = headers.begin(); it != headers.end(); ++it) |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
715 { |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
716 target += it->first + ": " + it->second + "\r\n"; |
1882
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
717 |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
718 std::string tmp; |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
719 Toolbox::ToLowerCase(tmp, it->first); |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
720 |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
721 if (tmp == "content-type") |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
722 { |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
723 hasContentType = true; |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
724 } |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
725 |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
726 if (tmp == "content-length") |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
727 { |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
728 hasContentLength = true; |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
729 } |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
730 |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
731 if (tmp == "mime-version") |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
732 { |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
733 hasMimeVersion = true; |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
734 } |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
735 } |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
736 |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
737 if (!hasContentType) |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
738 { |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
739 target += "Content-Type: " + contentType + "\r\n"; |
1882
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
740 } |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
741 |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
742 if (!hasContentLength) |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
743 { |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
744 target += "Content-Length: " + boost::lexical_cast<std::string>(length) + "\r\n"; |
1882
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
745 } |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
746 |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
747 if (!hasMimeVersion) |
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
748 { |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
749 target += "MIME-Version: 1.0\r\n\r\n"; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
750 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
751 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
752 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
753 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
754 void HttpOutput::StateMachine::SendMultipartItem(const void* item, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
755 size_t length, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
756 const std::map<std::string, std::string>& headers) |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
757 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
758 if (state_ != State_WritingMultipart) |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
759 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
760 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
1882
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
761 } |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
762 |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
763 std::string header; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
764 PrepareMultipartItemHeader(header, length, headers, multipartBoundary_, multipartContentType_); |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
765 stream_.Send(false, header.c_str(), header.size()); |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
766 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
767 if (length > 0) |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
768 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
769 stream_.Send(false, item, length); |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
770 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
771 |
1882
5cf2bd0abfa2
OrthancPluginSendMultipartItem2 for DICOMweb
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1875
diff
changeset
|
772 stream_.Send(false, "\r\n", 2); |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
773 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
774 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
775 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
776 void HttpOutput::StateMachine::CloseMultipart() |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
777 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
778 if (state_ != State_WritingMultipart) |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
779 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
780 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
781 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
782 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
783 // The two lines below might throw an exception, if the client has |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
784 // closed the connection. Such an error is ignored. |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
785 try |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
786 { |
1832
b7da58699f92
Fix formatting of multipart HTTP answers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1645
diff
changeset
|
787 std::string header = "--" + multipartBoundary_ + "--\r\n"; |
1430
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
788 stream_.Send(false, header.c_str(), header.size()); |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
789 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
790 catch (OrthancException&) |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
791 { |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
792 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
793 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
794 state_ = State_Done; |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
795 } |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
796 |
ad94a3583b07
Plugins can send answers as multipart messages
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
797 |
4672
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
798 void HttpOutput::StateMachine::SendStreamItem(const void* data, |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
799 size_t size) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
800 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
801 if (state_ != State_WritingStream) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
802 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
803 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
804 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
805 else |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
806 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
807 if (size > 0) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
808 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
809 stream_.Send(false, data, size); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
810 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
811 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
812 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
813 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
814 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
815 void HttpOutput::StateMachine::CloseStream() |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
816 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
817 if (state_ != State_WritingStream) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
818 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
819 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
820 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
821 else |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
822 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
823 state_ = State_Done; |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
824 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
825 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
826 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
827 |
3380
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
828 static void AnswerStreamAsBuffer(HttpOutput& output, |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
829 IHttpStreamAnswer& stream) |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
830 { |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
831 ChunkedBuffer buffer; |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
832 |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
833 while (stream.ReadNextChunk()) |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
834 { |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
835 if (stream.GetChunkSize() > 0) |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
836 { |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
837 buffer.AddChunk(stream.GetChunkContent(), stream.GetChunkSize()); |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
838 } |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
839 } |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
840 |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
841 std::string s; |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
842 buffer.Flatten(s); |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
843 |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
844 output.SetContentType(stream.GetContentType()); |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
845 |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
846 std::string filename; |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
847 if (stream.HasContentFilename(filename)) |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
848 { |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
849 output.SetContentFilename(filename.c_str()); |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
850 } |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
851 |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
852 output.Answer(s); |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
853 } |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
854 |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
855 |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
856 void HttpOutput::Answer(IHttpStreamAnswer& stream) |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
857 { |
1523
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
858 HttpCompression compression = stream.SetupHttpCompression(isGzipAllowed_, isDeflateAllowed_); |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
859 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
860 switch (compression) |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
861 { |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
862 case HttpCompression_None: |
3380
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
863 { |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
864 if (isGzipAllowed_ || isDeflateAllowed_) |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
865 { |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
866 // New in Orthanc 1.5.7: Compress streams without built-in |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
867 // compression, if requested by the "Accept-Encoding" HTTP |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
868 // header |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
869 AnswerStreamAsBuffer(*this, stream); |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
870 return; |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
871 } |
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
872 |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
873 break; |
3380
0528a6c36f3d
HTTP header "Accept-Encoding" is honored for streams without built-in support for compression
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3178
diff
changeset
|
874 } |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
875 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
876 case HttpCompression_Gzip: |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
877 stateMachine_.AddHeader("Content-Encoding", "gzip"); |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
878 break; |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
879 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
880 case HttpCompression_Deflate: |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
881 stateMachine_.AddHeader("Content-Encoding", "deflate"); |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
882 break; |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
883 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
884 default: |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
885 throw OrthancException(ErrorCode_ParameterOutOfRange); |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
886 } |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
887 |
1523
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
888 stateMachine_.SetContentLength(stream.GetContentLength()); |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
889 |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
890 std::string contentType = stream.GetContentType(); |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
891 if (contentType.empty()) |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
892 { |
2905
ae20fccdd867
refactoring mime types
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2805
diff
changeset
|
893 contentType = MIME_BINARY; |
1523
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
894 } |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
895 |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
896 stateMachine_.SetContentType(contentType.c_str()); |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
897 |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
898 std::string filename; |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
899 if (stream.HasContentFilename(filename)) |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
900 { |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
901 SetContentFilename(filename.c_str()); |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
902 } |
c388502a066d
testing FilesystemHttpSender
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1522
diff
changeset
|
903 |
1519
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
904 while (stream.ReadNextChunk()) |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
905 { |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
906 stateMachine_.SendBody(stream.GetChunkContent(), |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
907 stream.GetChunkSize()); |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
908 } |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
909 |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
910 stateMachine_.CloseBody(); |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
911 } |
8bd0d897763f
refactoring: IHttpStreamAnswer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1517
diff
changeset
|
912 |
3528
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
913 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
914 void HttpOutput::AnswerMultipartWithoutChunkedTransfer( |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
915 const std::string& subType, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
916 const std::string& contentType, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
917 const std::vector<const void*>& parts, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
918 const std::vector<size_t>& sizes, |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
919 const std::vector<const std::map<std::string, std::string>*>& headers) |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
920 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
921 if (parts.size() != sizes.size()) |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
922 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
923 throw OrthancException(ErrorCode_ParameterOutOfRange); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
924 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
925 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
926 stateMachine_.CheckHeadersCompatibilityWithMultipart(); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
927 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
928 std::string boundary, contentTypeHeader; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
929 PrepareMultipartMainHeader(boundary, contentTypeHeader, subType, contentType); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
930 SetContentType(contentTypeHeader); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
931 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
932 std::map<std::string, std::string> empty; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
933 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
934 ChunkedBuffer chunked; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
935 for (size_t i = 0; i < parts.size(); i++) |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
936 { |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
937 std::string partHeader; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
938 PrepareMultipartItemHeader(partHeader, sizes[i], headers[i] == NULL ? empty : *headers[i], |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
939 boundary, contentType); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
940 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
941 chunked.AddChunk(partHeader); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
942 chunked.AddChunk(parts[i], sizes[i]); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
943 chunked.AddChunk("\r\n"); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
944 } |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
945 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
946 chunked.AddChunk("--" + boundary + "--\r\n"); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
947 |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
948 std::string body; |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
949 chunked.Flatten(body); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
950 Answer(body); |
f6fe095f7130
don't open a multipart stream if plugin only sends one part
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3425
diff
changeset
|
951 } |
4672
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
952 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
953 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
954 void HttpOutput::AnswerWithoutBuffering(IHttpStreamAnswer& stream) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
955 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
956 std::string contentType = stream.GetContentType(); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
957 if (contentType.empty()) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
958 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
959 contentType = MIME_BINARY; |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
960 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
961 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
962 std::string filename; |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
963 if (stream.HasContentFilename(filename)) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
964 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
965 stateMachine_.AddHeader("Content-Disposition", "filename=\"" + std::string(filename) + "\""); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
966 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
967 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
968 stateMachine_.StartStream(contentType.c_str()); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
969 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
970 while (stream.ReadNextChunk()) |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
971 { |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
972 stateMachine_.SendStreamItem(stream.GetChunkContent(), stream.GetChunkSize()); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
973 } |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
974 |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
975 stateMachine_.CloseStream(); |
d9942d48fea7
ZipWriter::CancelStream(), ZipWriter::GetArchiveSize() and HttpOutput::AnswerWithoutBuffering()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4476
diff
changeset
|
976 } |
0 | 977 } |