1 /*
2 * SessionRequest.hpp
3 *
4 * Copyright (C) 2021 by RStudio, PBC
5 *
6 * Unless you have received this program directly from RStudio pursuant
7 * to the terms of a commercial license agreement with RStudio, then
8 * this program is licensed to you under the terms of version 3 of the
9 * GNU Affero General Public License. This program is distributed WITHOUT
10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13 *
14 */
15
16 #ifndef SESSION_REQUEST_HPP
17 #define SESSION_REQUEST_HPP
18
19 #include <shared_core/Error.hpp>
20 #include <core/system/Environment.hpp>
21
22 #include <session/http/SessionRequest.hpp>
23
24 #include <core/http/TcpIpBlockingClient.hpp>
25 #include <core/http/ConnectionRetryProfile.hpp>
26 #include <core/http/CSRFToken.hpp>
27
28 #ifndef _WIN32
29 #include <core/http/LocalStreamBlockingClient.hpp>
30 #include <session/SessionLocalStreams.hpp>
31 #endif
32
33 #include "session-config.h"
34
35 #ifdef RSTUDIO_SERVER
36 #include <server_core/sessions/SessionSignature.hpp>
37 #endif
38
39 #include <session/SessionConstants.hpp>
40
41 namespace rstudio {
42 namespace session {
43 namespace http {
44
45 // this function sends an request directly to the session; it's inlined so that
46 // it can be used both from the postback executable (which does not link with
47 // rsession) and the session itself
sendSessionRequest(const std::string & uri,const std::string & body,core::http::Response * pResponse)48 inline core::Error sendSessionRequest(const std::string& uri,
49 const std::string& body,
50 core::http::Response* pResponse)
51 {
52 // build request
53 core::http::Request request;
54 request.setMethod("POST");
55 request.setUri(uri);
56 request.setHeader("Accept", "*/*");
57 request.setHeader("Connection", "close");
58 request.setHeader("X-Session-Postback", "1");
59 request.setHeader(kRStudioUserIdentityDisplay, core::system::username());
60
61 // generate random CSRF token for request
62 std::string token = core::system::generateUuid();
63 request.setHeader(kCSRFTokenHeader, token);
64 request.addCookie(kCSRFTokenCookie, token);
65 request.setBody(body);
66
67 // first, attempt to send a plain old http request
68 std::string tcpipPort = core::system::getenv(kRSessionStandalonePortNumber);
69 if (tcpipPort.empty())
70 {
71 // if no standalone port, grab regular port number (desktop mode)
72 tcpipPort = core::system::getenv(kRSessionPortNumber);
73 }
74
75 if (!tcpipPort.empty())
76 {
77 std::string sharedSecret = core::system::getenv("RS_SHARED_SECRET");
78 if (!sharedSecret.empty())
79 {
80 // if we have a shared secret to use (like in desktop mode), simply stamp it on the request
81 request.setHeader("X-Shared-Secret", sharedSecret);
82 return core::http::sendRequest("127.0.0.1", tcpipPort, request, pResponse);
83 }
84 #ifdef RSTUDIO_SERVER
85 else
86 {
87 // otherwise, we need to authenticate via message signing with RSA crypto
88 core::Error error = server_core::sessions::signRequest(
89 core::system::getenv("RSTUDIO_SESSION_RSA_PRIVATE_KEY"),
90 request);
91 if (error)
92 return error;
93
94 return core::http::sendRequest("127.0.0.1", tcpipPort, request, pResponse);
95 }
96 #endif
97 }
98
99 #ifndef _WIN32
100 // otherwise, attempt communicating over a local stream (unix domain socket)
101 // determine stream path -- check server environment variable first
102 core::FilePath streamPath;
103 std::string stream = core::system::getenv(kRStudioSessionStream);
104 if (stream.empty())
105 {
106 // if no server environment variable, check desktop variant
107 streamPath = core::FilePath(core::system::getenv("RS_LOCAL_PEER"));
108 request.setHeader("X-Shared-Secret",
109 core::system::getenv("RS_SHARED_SECRET"));
110 }
111 else
112 {
113 streamPath = local_streams::streamPath(stream);
114 }
115 return core::http::sendRequest(streamPath, request, pResponse);
116 #endif
117
118 return core::Success();
119 }
120
121 } // namespace http
122 } // namespace session
123 } // namespace rstudio
124
125 #endif
126