22#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
24int HttpConnection::nextPageNumber=1;
31statusPage(
const char* code,
const char* title,
const char* detail)
36 s <<
"<!DOCTYPE html>"
37 "<html lang=\"en\"><head><meta charset=\"utf-8\" />"
38 "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />"
39 "<title>" << code <<
" " << title <<
"</title><style>"
40 "*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}"
41 "body{background:#0a0c0f;color:#c8d0da;"
42 "font-family:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;"
43 "font-size:13px;line-height:1.55;min-height:100vh;display:flex;align-items:center;"
44 "justify-content:center;padding:24px}"
45 ".card{background:#10141a;border:1px solid #1e2730;border-radius:3px;"
46 "padding:26px 28px;max-width:460px;width:100%}"
47 ".code{font-size:11px;font-weight:600;letter-spacing:.18em;color:#ffab00;"
48 "text-transform:uppercase;margin-bottom:8px}"
49 ".title{font-size:17px;font-weight:600;letter-spacing:.04em}"
50 "p{color:#7a8899;font-size:12px;margin-top:14px}"
51 "a{color:#40c4ff;text-decoration:none}a:hover{text-decoration:underline}"
52 "</style></head><body><div class=\"card\">"
53 "<div class=\"code\">HTTP " << code <<
"</div>"
54 "<div class=\"title\">" << title <<
"</div>"
55 "<p>" << detail <<
"</p>"
56 "<p><a href=\"/index.html\">← Back to Repro</a></p>"
57 "</div></body></html>";
69 mPageNumber(nextPageNumber++),
81 closesocket(mSock); mSock=0;
83 close(mSock); mSock=0;
91 if ( !mTxBuffer.
empty() )
105 int errNumSize =
sizeof(errNum);
106 getsockopt(mSock,SOL_SOCKET,SO_ERROR,(
char *)&errNum,(socklen_t *)&errNumSize);
107 InfoLog (<<
"Exception reading from socket "
108 << (
int)mSock <<
" code: " << errNum <<
"; closing connection");
114 bool ok = processSomeReads();
122 bool ok = processSomeWrites();
140 const bool isJson = (pType.
type() ==
"application" && pType.
subType() ==
"json");
146 mTxBuffer +=
"HTTP/1.0 401 Unauthorized"; mTxBuffer +=
Symbols::CRLF;
150 page = statusPage(
"401",
"Unauthorized",
151 "Valid administrator credentials are required to view this page.");
158 mTxBuffer +=
"HTTP/1.0 404 Not Found"; mTxBuffer +=
Symbols::CRLF;
162 page = statusPage(
"404",
"Not Found",
163 "The requested page does not exist on this server.");
170 mTxBuffer +=
"HTTP/1.0 301 Moved Permanently"; mTxBuffer +=
Symbols::CRLF;
171 mTxBuffer +=
"Location: /index.html"; mTxBuffer +=
Symbols::CRLF;
173 page = statusPage(
"301",
"Moved Permanently",
174 "This page has moved. Redirecting to the Repro home page.");
186 mTxBuffer +=
"HTTP/1.0 400 Bad Request" ; mTxBuffer +=
Symbols::CRLF;
192 mTxBuffer +=
"HTTP/1.0 405 Method Not Allowed" ; mTxBuffer +=
Symbols::CRLF;
198 mTxBuffer +=
"HTTP/1.0 500 Server failure" ; mTxBuffer +=
Symbols::CRLF;
204 mTxBuffer +=
"HTTP/1.0 501 Not Implemented" ; mTxBuffer +=
Symbols::CRLF;
210 mTxBuffer +=
"HTTP/1.0 503 Service Unavailable" ; mTxBuffer +=
Symbols::CRLF;
216 mTxBuffer +=
"HTTP/1.0 504 Gateway Timeout" ; mTxBuffer +=
Symbols::CRLF;
231 mTxBuffer +=
"HTTP/1.0 ";
245 mTxBuffer +=
"WWW-Authenticate: Basic realm=\"";
252 mTxBuffer += mHttpBase.
mRealm;
257 mTxBuffer +=
"Server: Repro Proxy " ;
260 mTxBuffer +=
"Mime-version: 1.0 " ; mTxBuffer +=
Symbols::CRLF;
261 mTxBuffer +=
"Pragma: no-cache " ; mTxBuffer +=
Symbols::CRLF;
262 mTxBuffer +=
"Content-Length: "; mTxBuffer += len; mTxBuffer +=
Symbols::CRLF;
264 mTxBuffer +=
"Content-Type: " ;
265 mTxBuffer += pType.
type() ;
276HttpConnection::processSomeReads()
278 const int bufSize = 8000;
283 int bytesRead = ::recv(mSock, buf, bufSize, 0);
285 int bytesRead = ::read(mSock, buf, bufSize);
294#if EAGAIN != EWOULDBLOCK
297 InfoLog (<<
"No data ready to read");
300 InfoLog (<<
"The call was interrupted by a signal before any data was read.");
306 InfoLog (<<
"fd is not a valid file descriptor or is not open for reading.");
309 InfoLog (<<
"fd is attached to an object which is unsuitable for reading.");
312 InfoLog (<<
"buf is outside your accessible address space.");
315 InfoLog (<<
"Some other error");
321 else if (bytesRead == 0)
323 InfoLog (<<
"Connection closed by remote " );
330 mRxBuffer +=
Data( buf, bytesRead );
339HttpConnection::tryParse()
352 pb.reset(pb.start());
356 const char* methodStart = pb.position();
366 pb.
data(method, methodStart);
368 const char* start = pb.skipWhitespace();
378 pb.
data( uri, start );
380 DebugLog (<<
"parse found method " << method <<
" URI " << uri );
381 mParsedRequest =
true;
389 pb.skipToChars(
"Authorization");
392 if ( pb.eof() )
DebugLog( <<
"Did not find Authorization header" );
393 pb.skipToChars(
"Basic" ); pb.skipN(6);
394 if ( pb.eof() )
DebugLog( <<
"Did not find Authorization basic " );
396 if ( pb.eof() )
DebugLog( <<
"Something weird in Auhtorization header " );
399 const char* a = pb.position();
400 pb.skipNonWhitespace();
403 DebugLog (<<
"parse found basic base64 auth data of " << buf );
409 const char* a1 = p.position();
412 const char* a2 = p.skipChar(
':');
414 password = p.
data(a2);
423 ErrLog (<<
"Some problem finding Authorization header in HTTP request" );
426 mHttpBase.
buildPage(method,uri,mPageNumber,user,password);
431HttpConnection::processSomeWrites()
433 if ( mTxBuffer.
empty() )
441 int bytesWritten = ::send( mSock, mTxBuffer.
data(), (
int)mTxBuffer.
size(), 0);
443 int bytesWritten = ::write(mSock, mTxBuffer.
data(), (
int)mTxBuffer.
size() );
449 InfoLog (<<
"HttpConnection failed write on " << mSock <<
" " <<
strError(e));
454 if (bytesWritten == (
int)mTxBuffer.
size() )
465 DebugLog( <<
"Wrote " << bytesWritten <<
" bytes - still need to do " << mTxBuffer );
#define resip_assert(x)
This file needs to work for both C and C++ code.
Handles cross-platform sockets compatibility.
virtual void buildPage(const resip::Data &method, const resip::Data &uri, int pageNumber, const resip::Data &user, const resip::Data &password)=0
bool process(resip::FdSet &fdset)
void buildFdSet(resip::FdSet &fdset)
HttpConnection(HttpBase &webAdmin, resip::Socket pSock)
void setPage(const resip::Data &page, int response, const resip::Mime &pType)
static const VersionUtils & instance()
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Data base64decode() const
Performs RFC 3548 Base 64 decoding of the contents of this data.
static const Data Empty
Constant that represents a zero-length data.
Data substr(size_type first, size_type count=Data::npos) const
Copies a portion of this Data into a new Data.
bool empty() const noexcept
Checks whether the Data is empty.
size_type size() const noexcept
Returns the number of bytes in this Data.
const char * data() const noexcept
Returns a pointer to the contents of this Data.
static const Data & getLocalHostName()
Object-oriented wrapper for your platform's file-descriptor set.
bool readyToWrite(Socket fd)
bool readyToRead(Socket fd)
bool hasException(Socket fd)
Represents the "media-type" element in the RFC 3261 grammar.
const Data & subType() const
const Data & type() const
Provides string-parsing functionality with protection from buffer overflow.
static const char * SPACE
static const char * CRLFCRLF
This Class is used to implement a primitive form of RPC using loose XML formatting.
dcm! – add UnusedChecking(_enum) below;
std::string strError(int err)