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 }