Mercurial > hg > orthanc
annotate OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.cpp @ 5066:956a9fed0aa8
fix
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 15 Aug 2022 14:22:50 +0200 |
parents | 43e613a7756b |
children | 0ea402b4d901 |
rev | line source |
---|---|
1525 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
1900 | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
1525 | 4 * Department, University Hospital of Liege, Belgium |
4870
43e613a7756b
upgrade to year 2022
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4831
diff
changeset
|
5 * Copyright (C) 2017-2022 Osimis S.A., Belgium |
43e613a7756b
upgrade to year 2022
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4831
diff
changeset
|
6 * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
1525 | 7 * |
8 * 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
|
9 * 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
|
10 * 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
|
11 * the License, or (at your option) any later version. |
1525 | 12 * |
13 * This program is distributed in the hope that it will be useful, but | |
14 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * 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
|
16 * Lesser General Public License for more details. |
1525 | 17 * |
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
|
18 * 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
|
19 * 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
|
20 * <http://www.gnu.org/licenses/>. |
1525 | 21 **/ |
22 | |
23 | |
24 #include "../PrecompiledHeaders.h" | |
25 #include "HttpStreamTranscoder.h" | |
26 | |
27 #include "../OrthancException.h" | |
28 #include "../Compression/ZlibCompressor.h" | |
29 | |
30 #include <string.h> // For memcpy() | |
31 #include <cassert> | |
32 | |
1548
e9325f3ac496
Bypass zlib uncompression if "StorageCompression" is enabled and HTTP client supports deflate
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1545
diff
changeset
|
33 #include <stdio.h> |
e9325f3ac496
Bypass zlib uncompression if "StorageCompression" is enabled and HTTP client supports deflate
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1545
diff
changeset
|
34 |
1525 | 35 namespace Orthanc |
36 { | |
37 void HttpStreamTranscoder::ReadSource(std::string& buffer) | |
38 { | |
39 if (source_.SetupHttpCompression(false, false) != HttpCompression_None) | |
40 { | |
41 throw OrthancException(ErrorCode_InternalError); | |
42 } | |
43 | |
44 uint64_t size = source_.GetContentLength(); | |
45 if (static_cast<uint64_t>(static_cast<size_t>(size)) != size) | |
46 { | |
47 throw OrthancException(ErrorCode_NotEnoughMemory); | |
48 } | |
49 | |
50 buffer.resize(static_cast<size_t>(size)); | |
51 size_t offset = 0; | |
52 | |
53 while (source_.ReadNextChunk()) | |
54 { | |
55 size_t chunkSize = static_cast<size_t>(source_.GetChunkSize()); | |
56 memcpy(&buffer[offset], source_.GetChunkContent(), chunkSize); | |
57 offset += chunkSize; | |
58 } | |
59 | |
60 if (offset != size) | |
61 { | |
62 throw OrthancException(ErrorCode_InternalError); | |
63 } | |
64 } | |
65 | |
66 | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
67 HttpCompression HttpStreamTranscoder::SetupZlibCompression(bool deflateAllowed) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
68 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
69 uint64_t size = source_.GetContentLength(); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
70 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
71 if (size == 0) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
72 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
73 return HttpCompression_None; |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
74 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
75 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
76 if (size < sizeof(uint64_t)) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
77 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
78 throw OrthancException(ErrorCode_CorruptedFile); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
79 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
80 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
81 if (deflateAllowed) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
82 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
83 bytesToSkip_ = sizeof(uint64_t); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
84 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
85 return HttpCompression_Deflate; |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
86 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
87 else |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
88 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
89 // TODO Use stream-based zlib decoding to reduce memory usage |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
90 std::string compressed; |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
91 ReadSource(compressed); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
92 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
93 uncompressed_.reset(new BufferHttpSender); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
94 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
95 ZlibCompressor compressor; |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
96 IBufferCompressor::Uncompress(uncompressed_->GetBuffer(), compressor, compressed); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
97 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
98 return HttpCompression_None; |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
99 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
100 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
101 |
4298 | 102 HttpStreamTranscoder::HttpStreamTranscoder(IHttpStreamAnswer &source, CompressionType compression) : |
103 source_(source), | |
104 sourceCompression_(compression), | |
105 bytesToSkip_(0), | |
106 skipped_(0), | |
107 currentChunkOffset_(0), | |
108 ready_(false) | |
109 { | |
110 } | |
111 | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
112 |
1525 | 113 HttpCompression HttpStreamTranscoder::SetupHttpCompression(bool gzipAllowed, |
114 bool deflateAllowed) | |
115 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
116 if (ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
117 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
118 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
119 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
120 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
121 ready_ = true; |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
122 |
1525 | 123 switch (sourceCompression_) |
124 { | |
125 case CompressionType_None: | |
126 return HttpCompression_None; | |
127 | |
128 case CompressionType_ZlibWithSize: | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
129 return SetupZlibCompression(deflateAllowed); |
1525 | 130 |
131 default: | |
132 throw OrthancException(ErrorCode_NotImplemented); | |
133 } | |
134 } | |
135 | |
4298 | 136 bool HttpStreamTranscoder::HasContentFilename(std::string &filename) |
137 { | |
138 return source_.HasContentFilename(filename); | |
139 } | |
140 | |
141 std::string HttpStreamTranscoder::GetContentType() | |
142 { | |
143 return source_.GetContentType(); | |
144 } | |
145 | |
1525 | 146 |
147 uint64_t HttpStreamTranscoder::GetContentLength() | |
148 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
149 if (!ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
150 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
151 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
152 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
153 |
1525 | 154 if (uncompressed_.get() != NULL) |
155 { | |
156 return uncompressed_->GetContentLength(); | |
157 } | |
158 else | |
159 { | |
160 uint64_t length = source_.GetContentLength(); | |
161 if (length < bytesToSkip_) | |
162 { | |
163 throw OrthancException(ErrorCode_InternalError); | |
164 } | |
165 | |
166 return length - bytesToSkip_; | |
167 } | |
168 } | |
169 | |
170 | |
171 bool HttpStreamTranscoder::ReadNextChunk() | |
172 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
173 if (!ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
174 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
175 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
176 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
177 |
1525 | 178 if (uncompressed_.get() != NULL) |
179 { | |
180 return uncompressed_->ReadNextChunk(); | |
181 } | |
182 | |
183 assert(skipped_ <= bytesToSkip_); | |
184 if (skipped_ == bytesToSkip_) | |
185 { | |
186 // We have already skipped the first bytes of the stream | |
187 currentChunkOffset_ = 0; | |
188 return source_.ReadNextChunk(); | |
189 } | |
190 | |
191 // This condition can only be true on the first call to "ReadNextChunk()" | |
192 for (;;) | |
193 { | |
194 assert(skipped_ < bytesToSkip_); | |
195 | |
196 bool ok = source_.ReadNextChunk(); | |
197 if (!ok) | |
198 { | |
199 throw OrthancException(ErrorCode_CorruptedFile); | |
200 } | |
201 | |
1545 | 202 size_t remaining = static_cast<size_t>(bytesToSkip_ - skipped_); |
1525 | 203 size_t s = source_.GetChunkSize(); |
204 | |
205 if (s < remaining) | |
206 { | |
207 skipped_ += s; | |
208 } | |
209 else if (s == remaining) | |
210 { | |
211 // We have skipped enough bytes, but we must read a new chunk | |
212 currentChunkOffset_ = 0; | |
213 skipped_ = bytesToSkip_; | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
214 return source_.ReadNextChunk(); |
1525 | 215 } |
216 else | |
217 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
218 // We have skipped enough bytes, and we have enough data in the current chunk |
1525 | 219 assert(s > remaining); |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
220 currentChunkOffset_ = remaining; |
1525 | 221 skipped_ = bytesToSkip_; |
222 return true; | |
223 } | |
224 } | |
225 } | |
226 | |
227 | |
228 const char* HttpStreamTranscoder::GetChunkContent() | |
229 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
230 if (!ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
231 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
232 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
233 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
234 |
1525 | 235 if (uncompressed_.get() != NULL) |
236 { | |
237 return uncompressed_->GetChunkContent(); | |
238 } | |
239 else | |
240 { | |
241 return source_.GetChunkContent() + currentChunkOffset_; | |
242 } | |
243 } | |
244 | |
245 size_t HttpStreamTranscoder::GetChunkSize() | |
246 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
247 if (!ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
248 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
249 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
250 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
251 |
1525 | 252 if (uncompressed_.get() != NULL) |
253 { | |
254 return uncompressed_->GetChunkSize(); | |
255 } | |
256 else | |
257 { | |
1545 | 258 return static_cast<size_t>(source_.GetChunkSize() - currentChunkOffset_); |
1525 | 259 } |
260 } | |
261 } |