From b8969775600ddd8225764840c05e27274c87ca72 Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Fri, 8 Jun 2018 12:11:15 -0700 Subject: [PATCH 1/2] Be lenient about Connection header contents when Upgrade header is present This is a workaround for https://github.com/rstudio/rstudio/issues/2940. It stops an erroneously sent "Connection: close" header from breaking an otherwise legit websocket request. --- src/httprequest.cpp | 13 +++++++++++-- src/httprequest.h | 4 +++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/httprequest.cpp b/src/httprequest.cpp index 365631d0..7cc6f670 100644 --- a/src/httprequest.cpp +++ b/src/httprequest.cpp @@ -414,11 +414,20 @@ void HttpRequest::_on_body_error(boost::shared_ptr pResponse) { // Message complete // ============================================================================ +bool HttpRequest::isUpgrade() const { + // Normally this should just be _parser.upgrade. But we also want to allow + // Upgrade: WebSocket + Connection: close, in order to work around an issue + // in RStudio Server's http proxying code with Firefox (only): + // https://github.com/rstudio/rstudio/issues/2940 + // https://github.com/rstudio/shiny/issues/2064 + return _parser.upgrade || _parser.flags & F_UPGRADE; +} + int HttpRequest::_on_message_complete(http_parser* pParser) { ASSERT_BACKGROUND_THREAD() trace("HttpRequest::_on_message_complete"); - if (pParser->upgrade) + if (isUpgrade()) return 0; boost::function)> schedule_bg_callback( @@ -706,7 +715,7 @@ void HttpRequest::_parse_http_data(char* buffer, const ssize_t n) { // buffer. _requestBuffer.insert(_requestBuffer.end(), buffer + parsed, buffer + n); - } else if (_parser.upgrade) { + } else if (isUpgrade()) { char* pData = buffer + parsed; size_t pDataLen = n - parsed; diff --git a/src/httprequest.h b/src/httprequest.h index fd1bf808..66de5830 100644 --- a/src/httprequest.h +++ b/src/httprequest.h @@ -126,7 +126,9 @@ class HttpRequest : public WebSocketConnectionCallbacks, std::string method() const; std::string url() const; const RequestHeaders& headers() const; - + // Is the request an Upgrade (i.e. WebSocket connection)? + bool isUpgrade() const; + void sendWSFrame(const char* pHeader, size_t headerSize, const char* pData, size_t dataSize, const char* pFooter, size_t footerSize); From afa32d06fc741a85d9f85077fedc2b8c95bba3cc Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Fri, 8 Jun 2018 12:46:15 -0700 Subject: [PATCH 2/2] Add news item --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index c1389a0a..84d06aaf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,6 +15,7 @@ httpuv 1.4.3.9002 * Fixed [#150](https://github.com/rstudio/httpuv/issues/150), [#151](https://github.com/rstudio/httpuv/issues/151): On some platforms, httpuv would fail to install from a zip file because R's `unzip()` function did not preserve the executable permission for `src/libuv/configure`. ([#152](https://github.com/rstudio/httpuv/pull/152)) +* Worked around an issue where Shiny apps couldn't be viewed when launched from RStudio Server using Firefox. ([#153](https://github.com/rstudio/httpuv/pull/153)) httpuv 1.4.3 ============