Logo ROOT   6.16/01
Reference Guide
THttpLongPollEngine.cxx
Go to the documentation of this file.
1// $Id$
2// Author: Sergey Linev 8/01/2018
3
4/*************************************************************************
5 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "THttpLongPollEngine.h"
13
14#include "THttpCallArg.h"
15#include "TSystem.h"
16
17#include <cstring>
18#include <cstdlib>
19
20//////////////////////////////////////////////////////////////////////////
21// //
22// THttpLongPollEngine //
23// //
24// Emulation of websocket with long poll requests //
25// Allows to send data from server to client without explicit request //
26// //
27//////////////////////////////////////////////////////////////////////////
28
29const std::string THttpLongPollEngine::gLongPollNope = "<<nope>>";
30
31//////////////////////////////////////////////////////////////////////////
32/// constructor
33
35{
36}
37
38//////////////////////////////////////////////////////////////////////////
39/// returns ID of the engine, created from this pointer
40
42{
43 const void *ptr = (const void *)this;
44 return TString::Hash((void *)&ptr, sizeof(void *));
45}
46
47//////////////////////////////////////////////////////////////////////////
48/// clear request, normally called shortly before destructor
49
51{
52 std::shared_ptr<THttpCallArg> poll;
53
54 {
55 std::lock_guard<std::mutex> grd(fMutex);
56 poll = std::move(fPoll);
57 }
58
59 if (poll) {
60 poll->Set404();
61 poll->NotifyCondition();
62 }
63}
64
65//////////////////////////////////////////////////////////////////////////
66/// Create raw buffer which should be send as reply
67/// For the raw mode all information must be send via binary response
68
69std::string THttpLongPollEngine::MakeBuffer(const void *buf, int len, const char *hdr)
70{
71 std::string res;
72
73 if (!fRaw) {
74 res.resize(len);
75 std::copy((const char *)buf, (const char *)buf + len, res.begin());
76 return res;
77 }
78
79 int hdrlen = hdr ? strlen(hdr) : 0;
80 std::string hdrstr = "bin:";
81 hdrstr.append(std::to_string(hdrlen));
82
83 while ((hdrstr.length() + 1 + hdrlen) % 8 != 0)
84 hdrstr.append(" ");
85 hdrstr.append(":");
86 if (hdrlen > 0)
87 hdrstr.append(hdr);
88
89 res.resize(hdrstr.length() + len);
90 std::copy(hdrstr.begin(), hdrstr.begin() + hdrstr.length(), res.begin());
91 std::copy((const char *)buf, (const char *)buf + len, res.begin() + hdrstr.length());
92
93 return res;
94}
95
96//////////////////////////////////////////////////////////////////////////
97/// Send binary data via connection
98
99void THttpLongPollEngine::Send(const void *buf, int len)
100{
101 std::shared_ptr<THttpCallArg> poll;
102
103 {
104 std::lock_guard<std::mutex> grd(fMutex);
105 poll = std::move(fPoll);
106 }
107
108 if(!poll) {
109 Error("Send", "Operation invoked before polling request obtained");
110 return;
111 }
112
113 std::string buf2 = MakeBuffer(buf, len);
114
115 poll->SetBinaryContent(std::move(buf2));
116 poll->NotifyCondition();
117}
118
119//////////////////////////////////////////////////////////////////////////
120/// Send binary data with text header via connection
121
122void THttpLongPollEngine::SendHeader(const char *hdr, const void *buf, int len)
123{
124 std::shared_ptr<THttpCallArg> poll;
125
126 {
127 std::lock_guard<std::mutex> grd(fMutex);
128 poll = std::move(fPoll);
129 }
130
131 if(!poll) {
132 Error("SendHeader", "Operation invoked before polling request obtained");
133 return;
134 }
135
136 std::string buf2 = MakeBuffer(buf, len, hdr);
137
138 poll->SetBinaryContent(std::move(buf2));
139 if (!fRaw)
140 poll->SetExtraHeader("LongpollHeader", hdr);
141 poll->NotifyCondition();
142}
143
144//////////////////////////////////////////////////////////////////////////
145/// Send const char data
146/// Either do it immediately or keep in internal buffer
147
149{
150 std::shared_ptr<THttpCallArg> poll;
151
152 {
153 std::lock_guard<std::mutex> grd(fMutex);
154 poll = std::move(fPoll);
155 }
156
157 if(!poll) {
158 Error("SendCharStart", "Operation invoked before polling request obtained");
159 return;
160 }
161
162 std::string sendbuf(fRaw ? "txt:" : "");
163 sendbuf.append(buf);
164
165 if (fRaw) poll->SetBinaryContent(std::move(sendbuf));
166 else poll->SetTextContent(std::move(sendbuf));
167 poll->NotifyCondition();
168}
169
170//////////////////////////////////////////////////////////////////////////////
171/// Preview data for given socket
172/// Method called by WS handler before processing websocket data
173/// Returns kTRUE when user should ignore such http request - it is for internal use
174
175Bool_t THttpLongPollEngine::PreProcess(std::shared_ptr<THttpCallArg> &arg)
176{
177 if (!strstr(arg->GetQuery(), "&dummy"))
178 return kFALSE;
179
180 arg->SetPostponed(); // mark http request as pending, http server should wait for notification
181
182 std::shared_ptr<THttpCallArg> poll;
183
184 {
185 std::lock_guard<std::mutex> grd(fMutex);
186 poll = std::move(fPoll);
187 fPoll = arg; // keep reference on polling request
188 }
189
190 if (arg == poll)
191 Fatal("PreviewData", "Submit same THttpCallArg object once again");
192
193 if (poll) {
194 Error("PreviewData", "Get next dummy request when previous not completed");
195 // if there are pending request, reply it immediately
196 // normally should never happen
197 if (fRaw) poll->SetBinaryContent(std::string("txt:") + gLongPollNope);
198 else poll->SetTextContent(std::string(gLongPollNope));
199 poll->NotifyCondition(); // inform http server that request is processed
200 }
201
202 // if arguments has "&dummy" string, user should not process it
203 return kTRUE;
204}
205
206//////////////////////////////////////////////////////////////////////////////
207/// Normally requests from client does not replied directly for longpoll socket
208/// Therefore one can use such request to send data, which was submitted before to the queue
209
210void THttpLongPollEngine::PostProcess(std::shared_ptr<THttpCallArg> &arg)
211{
212 if (fRaw) arg->SetBinaryContent(std::string("txt:") + gLongPollNope);
213 else arg->SetTextContent(std::string(gLongPollNope));
214}
215
216//////////////////////////////////////////////////////////////////////////////
217/// Indicate that polling requests is there and can be immediately invoked
218
220{
221 std::lock_guard<std::mutex> grd(fMutex);
222 return fPoll ? kTRUE : kFALSE;
223}
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
void Error(const char *location, const char *msgfmt,...)
void Fatal(const char *location, const char *msgfmt,...)
std::string MakeBuffer(const void *buf, int len, const char *hdr=nullptr)
!< default reply on the longpoll request
std::shared_ptr< THttpCallArg > fPoll
!< protect polling request to use it from different threads
void Send(const void *buf, int len) override
Send binary data via connection.
void SendHeader(const char *hdr, const void *buf, int len) override
Send binary data with text header via connection.
std::mutex fMutex
!< if true, only content can be used for data transfer
virtual Bool_t CanSendDirectly() override
Indicate that polling requests is there and can be immediately invoked.
THttpLongPollEngine(bool raw=false)
constructor
static const std::string gLongPollNope
!< hold polling request, which can be immediately used for the next sending
void ClearHandle(Bool_t) override
clear request, normally called shortly before destructor
void SendCharStar(const char *buf) override
Send const char data Either do it immediately or keep in internal buffer.
Bool_t PreProcess(std::shared_ptr< THttpCallArg > &arg) override
Preview data for given socket Method called by WS handler before processing websocket data Returns kT...
UInt_t GetId() const override
returns ID of the engine, created from this pointer
void PostProcess(std::shared_ptr< THttpCallArg > &arg) override
Normally requests from client does not replied directly for longpoll socket Therefore one can use suc...
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition: TString.cxx:626