Mercurial > hg > orthanc
comparison Plugins/Engine/OrthancPlugins.cpp @ 3528:f6fe095f7130
don't open a multipart stream if plugin only sends one part
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 26 Sep 2019 13:40:49 +0200 |
parents | 69e49fc044f8 |
children | 94f4a18a79cc |
comparison
equal
deleted
inserted
replaced
3527:40c80049fac7 | 3528:f6fe095f7130 |
---|---|
420 { | 420 { |
421 private: | 421 private: |
422 boost::mutex contextMutex_; | 422 boost::mutex contextMutex_; |
423 ServerContext* context_; | 423 ServerContext* context_; |
424 | 424 |
425 | |
426 public: | 425 public: |
427 class PluginHttpOutput : public boost::noncopyable | 426 class PluginHttpOutput : public boost::noncopyable |
428 { | 427 { |
429 private: | 428 private: |
429 enum MultipartState | |
430 { | |
431 MultipartState_None, | |
432 MultipartState_FirstPart, | |
433 MultipartState_SecondPart, | |
434 MultipartState_NextParts | |
435 }; | |
436 | |
430 HttpOutput& output_; | 437 HttpOutput& output_; |
431 std::auto_ptr<std::string> errorDetails_; | 438 std::auto_ptr<std::string> errorDetails_; |
432 bool logDetails_; | 439 bool logDetails_; |
440 MultipartState multipartState_; | |
441 std::string multipartSubType_; | |
442 std::string multipartContentType_; | |
443 std::string multipartFirstPart_; | |
444 std::map<std::string, std::string> multipartFirstHeaders_; | |
433 | 445 |
434 public: | 446 public: |
435 PluginHttpOutput(HttpOutput& output) : | 447 PluginHttpOutput(HttpOutput& output) : |
436 output_(output), | 448 output_(output), |
437 logDetails_(false) | 449 logDetails_(false), |
450 multipartState_(MultipartState_None) | |
438 { | 451 { |
439 } | 452 } |
440 | 453 |
441 HttpOutput& GetOutput() | 454 HttpOutput& GetOutput() |
442 { | 455 { |
443 return output_; | 456 if (multipartState_ == MultipartState_None) |
457 { | |
458 return output_; | |
459 } | |
460 else | |
461 { | |
462 // Must use "SendMultipartItem()" on multipart streams | |
463 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
464 } | |
444 } | 465 } |
445 | 466 |
446 void SetErrorDetails(const std::string& details, | 467 void SetErrorDetails(const std::string& details, |
447 bool logDetails) | 468 bool logDetails) |
448 { | 469 { |
470 { | 491 { |
471 return *errorDetails_; | 492 return *errorDetails_; |
472 } | 493 } |
473 } | 494 } |
474 | 495 |
496 void StartMultipart(const char* subType, | |
497 const char* contentType) | |
498 { | |
499 if (multipartState_ != MultipartState_None) | |
500 { | |
501 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
502 } | |
503 else | |
504 { | |
505 multipartState_ = MultipartState_FirstPart; | |
506 multipartSubType_ = subType; | |
507 multipartContentType_ = contentType; | |
508 } | |
509 } | |
510 | |
511 void SendMultipartItem(const void* data, | |
512 size_t size, | |
513 const std::map<std::string, std::string>& headers) | |
514 { | |
515 if (size != 0 && data == NULL) | |
516 { | |
517 throw OrthancException(ErrorCode_NullPointer); | |
518 } | |
519 | |
520 switch (multipartState_) | |
521 { | |
522 case MultipartState_None: | |
523 // Must call "StartMultipart()" before | |
524 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
525 | |
526 case MultipartState_FirstPart: | |
527 multipartFirstPart_.assign(reinterpret_cast<const char*>(data), size); | |
528 multipartFirstHeaders_ = headers; | |
529 multipartState_ = MultipartState_SecondPart; | |
530 break; | |
531 | |
532 case MultipartState_SecondPart: | |
533 // Start an actual stream for chunked transfer as soon as | |
534 // there are more than 2 elements in the multipart stream | |
535 output_.StartMultipart(multipartSubType_, multipartContentType_); | |
536 output_.SendMultipartItem(multipartFirstPart_.c_str(), multipartFirstPart_.size(), | |
537 multipartFirstHeaders_); | |
538 multipartFirstPart_.clear(); // Release memory | |
539 | |
540 output_.SendMultipartItem(data, size, headers); | |
541 multipartState_ = MultipartState_NextParts; | |
542 break; | |
543 | |
544 case MultipartState_NextParts: | |
545 output_.SendMultipartItem(data, size, headers); | |
546 break; | |
547 | |
548 default: | |
549 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
550 } | |
551 } | |
552 | |
475 void Close(OrthancPluginErrorCode error, | 553 void Close(OrthancPluginErrorCode error, |
476 PluginsErrorDictionary& dictionary) | 554 PluginsErrorDictionary& dictionary) |
477 { | 555 { |
478 if (error == OrthancPluginErrorCode_Success) | 556 if (error == OrthancPluginErrorCode_Success) |
479 { | 557 { |
480 if (GetOutput().IsWritingMultipart()) | 558 switch (multipartState_) |
481 { | 559 { |
482 GetOutput().CloseMultipart(); | 560 case MultipartState_None: |
561 assert(!output_.IsWritingMultipart()); | |
562 break; | |
563 | |
564 case MultipartState_FirstPart: // Multipart started, but no part was sent | |
565 case MultipartState_SecondPart: // Multipart started, first part is pending | |
566 { | |
567 assert(!output_.IsWritingMultipart()); | |
568 std::vector<const void*> parts; | |
569 std::vector<size_t> sizes; | |
570 std::vector<const std::map<std::string, std::string>*> headers; | |
571 | |
572 if (multipartState_ == MultipartState_SecondPart) | |
573 { | |
574 parts.push_back(multipartFirstPart_.c_str()); | |
575 sizes.push_back(multipartFirstPart_.size()); | |
576 headers.push_back(&multipartFirstHeaders_); | |
577 } | |
578 | |
579 output_.AnswerMultipartWithoutChunkedTransfer(multipartSubType_, multipartContentType_, | |
580 parts, sizes, headers); | |
581 break; | |
582 } | |
583 | |
584 case MultipartState_NextParts: | |
585 assert(output_.IsWritingMultipart()); | |
586 output_.CloseMultipart(); | |
587 | |
588 default: | |
589 throw OrthancException(ErrorCode_InternalError); | |
483 } | 590 } |
484 } | 591 } |
485 else | 592 else |
486 { | 593 { |
487 dictionary.LogError(error, false); | 594 dictionary.LogError(error, false); |
2909 // An exception might be raised in this function if the | 3016 // An exception might be raised in this function if the |
2910 // connection was closed by the HTTP client. | 3017 // connection was closed by the HTTP client. |
2911 const _OrthancPluginAnswerBuffer& p = | 3018 const _OrthancPluginAnswerBuffer& p = |
2912 *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters); | 3019 *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters); |
2913 | 3020 |
2914 HttpOutput& output = reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->GetOutput(); | |
2915 | |
2916 std::map<std::string, std::string> headers; // No custom headers | 3021 std::map<std::string, std::string> headers; // No custom headers |
2917 output.SendMultipartItem(p.answer, p.answerSize, headers); | 3022 reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->SendMultipartItem(p.answer, p.answerSize, headers); |
2918 } | 3023 } |
2919 | 3024 |
2920 | 3025 |
2921 void OrthancPlugins::ApplySendMultipartItem2(const void* parameters) | 3026 void OrthancPlugins::ApplySendMultipartItem2(const void* parameters) |
2922 { | 3027 { |
2923 // An exception might be raised in this function if the | 3028 // An exception might be raised in this function if the |
2924 // connection was closed by the HTTP client. | 3029 // connection was closed by the HTTP client. |
2925 const _OrthancPluginSendMultipartItem2& p = | 3030 const _OrthancPluginSendMultipartItem2& p = |
2926 *reinterpret_cast<const _OrthancPluginSendMultipartItem2*>(parameters); | 3031 *reinterpret_cast<const _OrthancPluginSendMultipartItem2*>(parameters); |
2927 HttpOutput& output = reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->GetOutput(); | |
2928 | 3032 |
2929 std::map<std::string, std::string> headers; | 3033 std::map<std::string, std::string> headers; |
2930 for (uint32_t i = 0; i < p.headersCount; i++) | 3034 for (uint32_t i = 0; i < p.headersCount; i++) |
2931 { | 3035 { |
2932 headers[p.headersKeys[i]] = p.headersValues[i]; | 3036 headers[p.headersKeys[i]] = p.headersValues[i]; |
2933 } | 3037 } |
2934 | 3038 |
2935 output.SendMultipartItem(p.answer, p.answerSize, headers); | 3039 reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->SendMultipartItem(p.answer, p.answerSize, headers); |
2936 } | 3040 } |
2937 | 3041 |
2938 | 3042 |
2939 void OrthancPlugins::DatabaseAnswer(const void* parameters) | 3043 void OrthancPlugins::DatabaseAnswer(const void* parameters) |
2940 { | 3044 { |
3205 | 3309 |
3206 case _OrthancPluginService_StartMultipartAnswer: | 3310 case _OrthancPluginService_StartMultipartAnswer: |
3207 { | 3311 { |
3208 const _OrthancPluginStartMultipartAnswer& p = | 3312 const _OrthancPluginStartMultipartAnswer& p = |
3209 *reinterpret_cast<const _OrthancPluginStartMultipartAnswer*>(parameters); | 3313 *reinterpret_cast<const _OrthancPluginStartMultipartAnswer*>(parameters); |
3210 HttpOutput& output = reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->GetOutput(); | 3314 reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->StartMultipart(p.subType, p.contentType); |
3211 output.StartMultipart(p.subType, p.contentType); | |
3212 return true; | 3315 return true; |
3213 } | 3316 } |
3214 | 3317 |
3215 case _OrthancPluginService_SendMultipartItem: | 3318 case _OrthancPluginService_SendMultipartItem: |
3216 ApplySendMultipartItem(parameters); | 3319 ApplySendMultipartItem(parameters); |