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