mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-09-03 10:51:12 +02:00
* this directory can be used to host some of your cracy stuff. yhtm, yjs and ysh will also parsed now. it is reachable with <boxip>/hosted/ * if exist a subdir named 'logos' in this directory you can use this as an external logo-dir for yweb too * path can be configured with '--with-hosted_httpddir=PATH'
223 lines
7.9 KiB
C++
223 lines
7.9 KiB
C++
//=============================================================================
|
|
// YHTTPD
|
|
// Response
|
|
//=============================================================================
|
|
|
|
// c
|
|
#include <cstdarg>
|
|
#include <cstdio>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
// c++
|
|
#include <string.h>
|
|
// system
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
// yhttpd
|
|
#include <yconfig.h>
|
|
#include <yhttpd.h>
|
|
#include "ytypes_globals.h"
|
|
#include "ylogging.h"
|
|
#include "ywebserver.h"
|
|
#include "yconnection.h"
|
|
#include "helper.h"
|
|
#include "yhook.h"
|
|
|
|
#ifdef Y_CONFIG_HAVE_SENDFILE
|
|
#include <sys/sendfile.h>
|
|
#endif
|
|
|
|
//=============================================================================
|
|
// Constructor & Destructor
|
|
//=============================================================================
|
|
CWebserverResponse::CWebserverResponse(CWebserver *pWebserver) {
|
|
Webserver = pWebserver;
|
|
CWebserverResponse();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
CWebserverResponse::CWebserverResponse() {
|
|
}
|
|
|
|
//=============================================================================
|
|
// Main Dispacher for Response
|
|
// To understand HOOKS reade yhook.cpp Comments!!!
|
|
//-----------------------------------------------------------------------------
|
|
// RFC 2616 / 6 Response
|
|
//
|
|
// After receiving and interpreting a request message, a server responds
|
|
// with an HTTP response message.
|
|
// Response =Status-Line ; generated by SendHeader
|
|
// *(( general-header ; generated by SendHeader
|
|
// | response-header ; generated by SendHeader
|
|
// | entity-header ) CRLF); generated by SendHeader
|
|
// CRLF ; generated by SendHeader
|
|
// [ message-body ] ; by HOOK Handling Loop or Sendfile
|
|
//=============================================================================
|
|
bool CWebserverResponse::SendResponse() {
|
|
// Init Hookhandler
|
|
Connection->HookHandler.session_init(Connection->Request.ParameterList,
|
|
Connection->Request.UrlData, (Connection->Request.HeaderList),
|
|
(Cyhttpd::ConfigList), Connection->Method, Connection->keep_alive);
|
|
//--------------------------------------------------------------
|
|
// HOOK Handling Loop [ PREPARE response hook ]
|
|
// Checking and Preperation: Auth, static, cache, ...
|
|
//--------------------------------------------------------------
|
|
|
|
do {
|
|
if (Connection->RequestCanceled)
|
|
return false;
|
|
|
|
Connection->HookHandler.Hooks_PrepareResponse();
|
|
if (Connection->HookHandler.status == HANDLED_ERROR
|
|
|| Connection->HookHandler.status == HANDLED_ABORT) {
|
|
log_level_printf(2, "Response Prepare Hook found but Error\n");
|
|
Write(Connection->HookHandler.BuildHeader());
|
|
Write(Connection->HookHandler.yresult);
|
|
return false;
|
|
}
|
|
// URL has new value. Analyze new URL for SendFile
|
|
else if (Connection->HookHandler.status == HANDLED_SENDFILE
|
|
|| Connection->HookHandler.status == HANDLED_REWRITE) {
|
|
Connection->Request.analyzeURL(Connection->HookHandler.NewURL);
|
|
Connection->HookHandler.UrlData = Connection->Request.UrlData;
|
|
}
|
|
if (Connection->HookHandler.status == HANDLED_REDIRECTION) {
|
|
Write(Connection->HookHandler.BuildHeader());
|
|
return false;
|
|
}
|
|
} while (Connection->HookHandler.status == HANDLED_REWRITE);
|
|
|
|
// Prepare = NOT_MODIFIED ?
|
|
if (Connection->HookHandler.httpStatus == HTTP_NOT_MODIFIED) {
|
|
Write(Connection->HookHandler.BuildHeader());
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// HOOK Handling Loop [ response hook ]
|
|
// Production
|
|
//--------------------------------------------------------------
|
|
if (Connection->HookHandler.status != HANDLED_SENDFILE)
|
|
do {
|
|
if (Connection->RequestCanceled)
|
|
return false;
|
|
|
|
Connection->HookHandler.Hooks_SendResponse();
|
|
if ((Connection->HookHandler.status == HANDLED_READY)
|
|
|| (Connection->HookHandler.status == HANDLED_CONTINUE)) {
|
|
log_level_printf(2, "Response Hook Output. Status:%d\n", Connection->HookHandler.status);
|
|
Write(Connection->HookHandler.BuildHeader());
|
|
if (Connection->Method != M_HEAD)
|
|
Write(Connection->HookHandler.yresult);
|
|
if (Connection->HookHandler.status != HANDLED_CONTINUE)
|
|
return true;
|
|
} else if (Connection->HookHandler.status == HANDLED_ERROR) {
|
|
log_level_printf(2, "Response Hook found but Error\n");
|
|
Write(Connection->HookHandler.BuildHeader());
|
|
if (Connection->Method != M_HEAD)
|
|
Write(Connection->HookHandler.yresult);
|
|
return false;
|
|
} else if (Connection->HookHandler.status == HANDLED_ABORT)
|
|
return false;
|
|
// URL has new value. Analyze new URL for SendFile
|
|
else if (Connection->HookHandler.status == HANDLED_SENDFILE
|
|
|| Connection->HookHandler.status == HANDLED_REWRITE) {
|
|
Connection->Request.analyzeURL(Connection->HookHandler.NewURL);
|
|
Connection->HookHandler.UrlData = Connection->Request.UrlData;
|
|
}
|
|
if (Connection->HookHandler.status == HANDLED_REDIRECTION) {
|
|
Write(Connection->HookHandler.BuildHeader());
|
|
return false;
|
|
}
|
|
} while (Connection->HookHandler.status == HANDLED_REWRITE);
|
|
|
|
// Send static file
|
|
if (Connection->HookHandler.status == HANDLED_SENDFILE
|
|
&& !Connection->RequestCanceled) {
|
|
bool cache = true;
|
|
// if(Connection->HookHandler.UrlData["path"] == "/tmp/")//TODO: un-cachable dirs
|
|
// cache = false;
|
|
Write(Connection->HookHandler.BuildHeader(cache));
|
|
if (Connection->Method != M_HEAD)
|
|
Sendfile(Connection->Request.UrlData["url"]);
|
|
return true;
|
|
}
|
|
|
|
// arrived here? = error!
|
|
SendError( HTTP_NOT_FOUND);
|
|
return false;
|
|
}
|
|
|
|
//=============================================================================
|
|
// Output
|
|
//=============================================================================
|
|
void CWebserverResponse::SendHeader(HttpResponseType responseType, bool cache,
|
|
std::string ContentType) {
|
|
Connection->HookHandler.SetHeader(responseType, ContentType);
|
|
Write(Connection->HookHandler.BuildHeader(cache));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// BASIC Send over Socket for Strings (char*)
|
|
//-----------------------------------------------------------------------------
|
|
bool CWebserverResponse::WriteData(char const * data, long length) {
|
|
if (Connection->RequestCanceled)
|
|
return false;
|
|
if (Connection->sock->Send(data, length) == -1) {
|
|
log_level_printf(1, "response canceled: %s\n", strerror(errno));
|
|
Connection->RequestCanceled = true;
|
|
return false;
|
|
} else
|
|
return true;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
#define bufferlen 4*1024
|
|
void CWebserverResponse::printf(const char *fmt, ...) {
|
|
char buffer[bufferlen];
|
|
va_list arglist;
|
|
va_start(arglist, fmt);
|
|
vsnprintf(buffer, bufferlen, fmt, arglist);
|
|
va_end(arglist);
|
|
Write(buffer);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
bool CWebserverResponse::Write(char const *text) {
|
|
return WriteData(text, strlen(text));
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
bool CWebserverResponse::WriteLn(char const *text) {
|
|
if (!WriteData(text, strlen(text)))
|
|
return false;
|
|
return WriteData("\r\n", 2);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool CWebserverResponse::Sendfile(std::string filename) {
|
|
if (Connection->RequestCanceled)
|
|
return false;
|
|
int filed = open(filename.c_str(), O_RDONLY);
|
|
if (filed != -1) //can access file?
|
|
{
|
|
if (!Connection->sock->SendFile(filed))
|
|
Connection->RequestCanceled = true;
|
|
close(filed);
|
|
}
|
|
return (filed != -1);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Send File: Determine MIME-Type fro File-Extention
|
|
//-----------------------------------------------------------------------------
|
|
std::string CWebserverResponse::GetContentType(std::string ext) {
|
|
std::string ctype = "text/plain";
|
|
ext = string_tolower(ext);
|
|
for (unsigned int i = 0; i < (sizeof(MimeFileExtensions)
|
|
/ sizeof(MimeFileExtensions[0])); i++)
|
|
if (MimeFileExtensions[i].fileext == ext) {
|
|
ctype = MimeFileExtensions[i].mime;
|
|
break;
|
|
}
|
|
return ctype;
|
|
}
|