Mercurial > hg > orthanc
annotate OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.cpp @ 4544:ae63b301d522 Orthanc-1.7.4
close branch
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 02 Mar 2021 16:52:26 +0100 |
parents | bf7b9edf6b81 |
children | db3932f9660d |
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 |
3640
94f4a18a79cc
upgrade to year 2020
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
5 * Copyright (C) 2017-2020 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 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
101 |
1525 | 102 HttpCompression HttpStreamTranscoder::SetupHttpCompression(bool gzipAllowed, |
103 bool deflateAllowed) | |
104 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
105 if (ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
106 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
107 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
108 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
109 |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
110 ready_ = true; |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
111 |
1525 | 112 switch (sourceCompression_) |
113 { | |
114 case CompressionType_None: | |
115 return HttpCompression_None; | |
116 | |
117 case CompressionType_ZlibWithSize: | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
118 return SetupZlibCompression(deflateAllowed); |
1525 | 119 |
120 default: | |
121 throw OrthancException(ErrorCode_NotImplemented); | |
122 } | |
123 } | |
124 | |
125 | |
126 uint64_t HttpStreamTranscoder::GetContentLength() | |
127 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
128 if (!ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
129 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
130 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
131 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
132 |
1525 | 133 if (uncompressed_.get() != NULL) |
134 { | |
135 return uncompressed_->GetContentLength(); | |
136 } | |
137 else | |
138 { | |
139 uint64_t length = source_.GetContentLength(); | |
140 if (length < bytesToSkip_) | |
141 { | |
142 throw OrthancException(ErrorCode_InternalError); | |
143 } | |
144 | |
145 return length - bytesToSkip_; | |
146 } | |
147 } | |
148 | |
149 | |
150 bool HttpStreamTranscoder::ReadNextChunk() | |
151 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
152 if (!ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
153 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
154 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
155 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
156 |
1525 | 157 if (uncompressed_.get() != NULL) |
158 { | |
159 return uncompressed_->ReadNextChunk(); | |
160 } | |
161 | |
162 assert(skipped_ <= bytesToSkip_); | |
163 if (skipped_ == bytesToSkip_) | |
164 { | |
165 // We have already skipped the first bytes of the stream | |
166 currentChunkOffset_ = 0; | |
167 return source_.ReadNextChunk(); | |
168 } | |
169 | |
170 // This condition can only be true on the first call to "ReadNextChunk()" | |
171 for (;;) | |
172 { | |
173 assert(skipped_ < bytesToSkip_); | |
174 | |
175 bool ok = source_.ReadNextChunk(); | |
176 if (!ok) | |
177 { | |
178 throw OrthancException(ErrorCode_CorruptedFile); | |
179 } | |
180 | |
1545 | 181 size_t remaining = static_cast<size_t>(bytesToSkip_ - skipped_); |
1525 | 182 size_t s = source_.GetChunkSize(); |
183 | |
184 if (s < remaining) | |
185 { | |
186 skipped_ += s; | |
187 } | |
188 else if (s == remaining) | |
189 { | |
190 // We have skipped enough bytes, but we must read a new chunk | |
191 currentChunkOffset_ = 0; | |
192 skipped_ = bytesToSkip_; | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
193 return source_.ReadNextChunk(); |
1525 | 194 } |
195 else | |
196 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
197 // We have skipped enough bytes, and we have enough data in the current chunk |
1525 | 198 assert(s > remaining); |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
199 currentChunkOffset_ = remaining; |
1525 | 200 skipped_ = bytesToSkip_; |
201 return true; | |
202 } | |
203 } | |
204 } | |
205 | |
206 | |
207 const char* HttpStreamTranscoder::GetChunkContent() | |
208 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
209 if (!ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
210 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
211 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
212 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
213 |
1525 | 214 if (uncompressed_.get() != NULL) |
215 { | |
216 return uncompressed_->GetChunkContent(); | |
217 } | |
218 else | |
219 { | |
220 return source_.GetChunkContent() + currentChunkOffset_; | |
221 } | |
222 } | |
223 | |
224 size_t HttpStreamTranscoder::GetChunkSize() | |
225 { | |
1526
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
226 if (!ready_) |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
227 { |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
228 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
229 } |
096a8af528c9
fix streams, initialization/finalization of libcurl and openssl
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1525
diff
changeset
|
230 |
1525 | 231 if (uncompressed_.get() != NULL) |
232 { | |
233 return uncompressed_->GetChunkSize(); | |
234 } | |
235 else | |
236 { | |
1545 | 237 return static_cast<size_t>(source_.GetChunkSize() - currentChunkOffset_); |
1525 | 238 } |
239 } | |
240 } |