Mercurial > hg > orthanc
comparison Core/HttpServer/HttpOutput.cpp @ 1430:ad94a3583b07
Plugins can send answers as multipart messages
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 29 Jun 2015 17:47:34 +0200 |
parents | 6e7e5ed91c2d |
children | f967bdf8534e |
comparison
equal
deleted
inserted
replaced
1429:7366a0bdda6a | 1430:ad94a3583b07 |
---|---|
149 LOG(ERROR) << "Because of keep-alive connections, the entire body must be sent at once or Content-Length must be given"; | 149 LOG(ERROR) << "Because of keep-alive connections, the entire body must be sent at once or Content-Length must be given"; |
150 throw OrthancException(ErrorCode_BadSequenceOfCalls); | 150 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
151 } | 151 } |
152 } | 152 } |
153 | 153 |
154 if (state_ == State_WritingMultipart) | |
155 { | |
156 throw OrthancException(ErrorCode_InternalError); | |
157 } | |
158 | |
154 if (state_ == State_WritingHeader) | 159 if (state_ == State_WritingHeader) |
155 { | 160 { |
156 // Send the HTTP header before writing the body | 161 // Send the HTTP header before writing the body |
157 | 162 |
158 stream_.OnHttpStatusReceived(status_); | 163 stream_.OnHttpStatusReceived(status_); |
268 | 273 |
269 void HttpOutput::SendBody() | 274 void HttpOutput::SendBody() |
270 { | 275 { |
271 stateMachine_.SendBody(NULL, 0); | 276 stateMachine_.SendBody(NULL, 0); |
272 } | 277 } |
278 | |
279 | |
280 void HttpOutput::StateMachine::StartMultipart(const std::string& subType, | |
281 const std::string& contentType) | |
282 { | |
283 if (subType != "mixed" && | |
284 subType != "related") | |
285 { | |
286 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
287 } | |
288 | |
289 if (keepAlive_) | |
290 { | |
291 LOG(ERROR) << "Multipart answers are not implemented together with keep-alive connections"; | |
292 throw OrthancException(ErrorCode_NotImplemented); | |
293 } | |
294 | |
295 if (state_ != State_WritingHeader) | |
296 { | |
297 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
298 } | |
299 | |
300 if (status_ != HttpStatus_200_Ok) | |
301 { | |
302 SendBody(NULL, 0); | |
303 return; | |
304 } | |
305 | |
306 stream_.OnHttpStatusReceived(status_); | |
307 | |
308 std::string header = "HTTP/1.1 200 OK\r\n"; | |
309 | |
310 // Possibly add the cookies | |
311 for (std::list<std::string>::const_iterator | |
312 it = headers_.begin(); it != headers_.end(); ++it) | |
313 { | |
314 if (!Toolbox::StartsWith(*it, "Set-Cookie: ")) | |
315 { | |
316 LOG(ERROR) << "The only headers that can be set in multipart answers are Set-Cookie (here: " << *it << " is set)"; | |
317 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
318 } | |
319 | |
320 header += *it; | |
321 } | |
322 | |
323 multipartBoundary_ = Toolbox::GenerateUuid(); | |
324 multipartContentType_ = contentType; | |
325 header += "Content-Type: multipart/related; type=multipart/" + subType + "; boundary=" + multipartBoundary_ + "\r\n\r\n"; | |
326 | |
327 stream_.Send(true, header.c_str(), header.size()); | |
328 state_ = State_WritingMultipart; | |
329 } | |
330 | |
331 | |
332 void HttpOutput::StateMachine::SendMultipartItem(const void* item, size_t length) | |
333 { | |
334 std::string header = "--" + multipartBoundary_ + "\n"; | |
335 header += "Content-Type: " + multipartContentType_ + "\n"; | |
336 header += "Content-Length: " + boost::lexical_cast<std::string>(length) + "\n"; | |
337 header += "MIME-Version: 1.0\n\n"; | |
338 | |
339 stream_.Send(false, header.c_str(), header.size()); | |
340 | |
341 if (length > 0) | |
342 { | |
343 stream_.Send(false, item, length); | |
344 } | |
345 | |
346 stream_.Send(false, "\n", 1); | |
347 } | |
348 | |
349 | |
350 void HttpOutput::StateMachine::CloseMultipart() | |
351 { | |
352 if (state_ != State_WritingMultipart) | |
353 { | |
354 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
355 } | |
356 | |
357 // The two lines below might throw an exception, if the client has | |
358 // closed the connection. Such an error is ignored. | |
359 try | |
360 { | |
361 std::string header = "--" + multipartBoundary_ + "--\n"; | |
362 stream_.Send(false, header.c_str(), header.size()); | |
363 } | |
364 catch (OrthancException&) | |
365 { | |
366 } | |
367 | |
368 state_ = State_Done; | |
369 } | |
370 | |
371 | |
372 void HttpOutput::SendMultipartItem(const std::string& item) | |
373 { | |
374 if (item.size() > 0) | |
375 { | |
376 stateMachine_.SendMultipartItem(item.c_str(), item.size()); | |
377 } | |
378 else | |
379 { | |
380 stateMachine_.SendMultipartItem(NULL, 0); | |
381 } | |
382 } | |
273 } | 383 } |