Skip to content

Commit

Permalink
Embed Mongoose server and PHP CGI (#221)
Browse files Browse the repository at this point in the history
PHP Desktop for Linux now displays index.php with phpinfo().
  • Loading branch information
cztomczak committed Dec 1, 2018
1 parent b927470 commit 2f73d49
Show file tree
Hide file tree
Showing 11 changed files with 300 additions and 7 deletions.
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ CCFLAGS += $(shell pkg-config --cflags glib-2.0 gtk+-3.0)

CFLAGS_OPTIMIZE = -O3 -fvisibility=hidden

LDFLAGS = -Wl,-rpath,. -Wl,-rpath,"\$$ORIGIN" -lX11 -lcef -lcef_dll_wrapper
LDFLAGS = -Wl,-rpath,. -Wl,-rpath,"\$$ORIGIN" -lX11 -lcef -lcef_dll_wrapper -Wl,--as-needed -ldl
LDFLAGS += $(shell pkg-config --libs glib-2.0 gtk+-3.0)

OBJS=\
src/main.o \
src/app.o \
src/client_handler.o \
src/mongoose.o \
src/mongoose_server.o \
src/utils.o \

CC=g++
.PHONY: clean release debug
Expand All @@ -33,6 +36,9 @@ debug: $(TARGET)
%.o : %.cpp
+$(CC) -c -o $@ -MD -MP -MF $@.deps $(CCFLAGS) $(CFLAGS_OPTIMIZE) $<

%.o : %.c
+gcc -c -o $@ -MD -MP -MF $@.deps -g -std=c99 -O2 -W -Wall -Werror -pedantic -pthread -pipe $<

$(TARGET): $(OBJS)
+$(CC) $(CCFLAGS) $(CFLAGS_OPTIMIZE) -o $@ $(OBJS) $(LDFLAGS)

Expand Down
5 changes: 5 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ make -R -f Makefile "$@"
rc=$?;
if [[ ${rc} = 0 ]]; then
echo "OK phpdesktop was built";
cp src/php.ini build/bin/
if [[ -d build/bin/www ]]; then
rm -r build/bin/www
fi
cp -r src/www/ build/bin/
./build/bin/phpdesktop
rm -r blob_storage/
rm -r GPUCache/
Expand Down
44 changes: 41 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "app.h"
#include "client_handler.h"
#include "utils.h"
#include "mongoose_server.h"

#include "include/base/cef_logging.h"
#include "include/wrapper/cef_helpers.h"
Expand All @@ -16,6 +18,8 @@
#include <cstring>
#include <cerrno>

std::string g_cgi_env_from_argv = "";


int XErrorHandlerImpl(Display* display, XErrorEvent* event) {
LOG(WARNING) << "X error received: "
Expand All @@ -33,6 +37,24 @@ int XIOErrorHandlerImpl(Display* display) {
}

int main(int argc, char **argv) {
LOG(INFO) << "Executable directory: " << executable_dir();

// Passing ENV variables to PHP using the --cgi-environment
// command line arg passed to app.
if (argv) {
for (int i = 0; i < argc; i++) {
std::string arg = argv[i];
size_t pos = arg.find("=");
if (pos != std::string::npos) {
std::string name = arg.substr(0, pos);
std::string value = arg.substr(pos+1, std::string::npos);
if (name == "--cgi-environment" && value.length()) {
g_cgi_env_from_argv.assign(value);
}
}
}
}

// Create a copy of |argv| on Linux because Chromium mangles the value
// internally (see CEF issue #620).
CefScopedArgArray scoped_arg_array(argc, argv);
Expand Down Expand Up @@ -74,6 +96,15 @@ int main(int argc, char **argv) {
return exit_code;
}

// Single instance application
// @TODO

// Main window title
// @TODO from settings.json

// Start Mongoose server
MongooseStart();

// Install xlib error handlers so that the application won't be terminated
// on non-fatal errors. X11 errors appearing in debug logs usually can be
// ignored.
Expand All @@ -83,8 +114,12 @@ int main(int argc, char **argv) {
// Specify CEF global settings here.
CefSettings settings;
settings.no_sandbox = true;
CefString( &settings.log_file ) = "debug.log";
settings.log_severity = LOGSEVERITY_INFO;
CefString( &settings.log_file ) = "debug.log"; // @TODO from settings.json
settings.log_severity = LOGSEVERITY_INFO; // @TODO from settings.json
// @TODO cache_path settings.json option

// Remote debugging port
// @todo from settings.json

// App implements application-level callbacks for the browser
// process.
Expand Down Expand Up @@ -113,11 +148,14 @@ int main(int argc, char **argv) {
CefBrowserHost::CreateBrowserSync(
window_info,
ClientHandler::GetInstance(),
"https://www.google.com/",
MongooseGetUrl(),
browser_settings,
NULL);

CefRunMessageLoop();

LOG(INFO) << "Stop Mongoose server";
MongooseStop();

LOG(INFO) << "Shutdown CEF";
CefShutdown();
Expand Down
12 changes: 9 additions & 3 deletions src/mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,9 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
(void) execle(prog, prog, NULL, envp);
cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
} else {
// char prog_abspath[PATH_MAX];
// strcpy(prog_abspath, dir);
// strcat(prog_abspath, prog);
(void) execle(interp, interp, prog, NULL, envp);
cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
strerror(ERRNO));
Expand Down Expand Up @@ -1832,6 +1835,7 @@ static void support_path_info_for_cgi_scripts(
struct mg_connection *conn, char *buf,
size_t buf_len, struct file *filep) {
char *p;
if (buf_len) {} // unused paramter during compilation
// Support PATH_INFO for CGI scripts.
for (p = buf + strlen(buf); p > buf + 1; p--) {
if (*p == '/') {
Expand Down Expand Up @@ -3387,8 +3391,8 @@ static void prepare_cgi_environment(struct mg_connection *conn,
if (prog2[i] == '/') {
prog2[i] = '\\';
}
#endif
}
#endif

addenv(blk, "SCRIPT_FILENAME=%s", prog2);
addenv(blk, "PATH_TRANSLATED=%s", prog2);
Expand Down Expand Up @@ -4689,14 +4693,15 @@ static void close_all_listening_sockets(struct mg_context *ctx) {
static int is_valid_port(unsigned int port) {
// PHP Desktop Fix:
// Allow value of 0, so that OS assigns a random free port.
return port >= 0 && port < 0xffff;
return port < 0xffff;
}

// Valid listening port specification is: [ip_address:]port[s]
// Examples: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
// TODO(lsm): add parsing of the IPv6 address
static int parse_port_string(const struct vec *vec, struct socket *so) {
unsigned int a, b, c, d, ch, len, port;
unsigned int a, b, c, d, ch, port;
int len;
#if defined(USE_IPV6)
char buf[100];
#endif
Expand Down Expand Up @@ -5518,6 +5523,7 @@ void mg_stop(struct mg_context *ctx) {
}

void mg_stop_immediately(struct mg_context *ctx) {
if (ctx) {} // unused parameter warning
// Stopping Mongoose and freeing resources will hang when
// used with IE webbrowser control. It seems that IE is not
// freeing reources properly, it does it with some delay.
Expand Down
155 changes: 155 additions & 0 deletions src/mongoose_server.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright (c) 2018 PHP Desktop, see the Authors file.
// All rights reserved. Licensed under BSD 3-clause license.
// Project website: https://github.com/cztomczak/phpdesktop

#include "mongoose.h"
#include "utils.h"
#include "version.h"
#include "include/base/cef_logging.h"

std::string g_mongoose_port = "0"; // @TODO from settings.json
std::string g_mongoose_ip_address = "127.0.0.1"; // @TODO from settings.json
std::string g_mongoose_url = "";

struct mg_context* g_mongoose_context = 0;
extern std::string g_cgi_env_from_argv;

static int mongoose_log_message(const struct mg_connection* conn,
const char *message) {
// Called when mongoose is about to log a message. If callback returns
// non-zero, mongoose does not log anything.
LOG(WARNING) << message;
return 0;
}

static void mongoose_end_request(const struct mg_connection* conn,
int reply_status_code) {
// Called when mongoose has finished processing request.
mg_request_info* request = mg_get_request_info(
const_cast<mg_connection*>(conn));
std::string message;
message.append(request->request_method);
message.append(" ");
std::stringstream ss;
ss << reply_status_code;
message.append(ss.str());
message.append(" ");
message.append(request->uri);
if (request->query_string) {
message.append("?");
message.append(request->query_string);
}
LOG(INFO) << message;
}

bool MongooseStart() {
LOG(INFO) << "Start Mongoose server";

// Temp directory
std::string cgi_temp_dir = "/tmp";
// @TODO load cgi_temp_dir from settings.json
char const* tmp = getenv("TMP");
if (tmp != NULL) {
cgi_temp_dir.assign(tmp);
} else {
char const* temp = getenv("TEMP");
if (temp != NULL) {
cgi_temp_dir.assign(temp);
} else {
char const* tmpdir = getenv("TMPDIR");
if (tmpdir != NULL) {
cgi_temp_dir.assign(tmpdir);
}
}
}

// CGI environment variables
std::string cgi_env = "";
cgi_env.append("TMP=").append(cgi_temp_dir).append(",");
cgi_env.append("TEMP=").append(cgi_temp_dir).append(",");
cgi_env.append("TMPDIR=").append(cgi_temp_dir).append(",");
if (g_mongoose_ip_address != "*") {
cgi_env.append("SERVER_NAME=").append(g_mongoose_ip_address)
.append(",");
}
cgi_env.append("PHPDESKTOP_VERSION=").append(PHPDESKTOP_VERSION);
if (g_cgi_env_from_argv.length()) {
cgi_env.append(",").append(g_cgi_env_from_argv);
}
LOG(INFO) << "CGI environment variables set: " << cgi_env;

// Document root
std::string document_root = executable_dir().append("/www");
LOG(INFO) << "document_root=" << document_root;

// Listening ports
// @TODO from settings.json
std::string listening_ports;
if (g_mongoose_ip_address == "*") {
listening_ports = g_mongoose_port;
} else {
listening_ports = g_mongoose_ip_address + ":" + g_mongoose_port;
}

// CGI interpreter
std::string cgi_interpreter = executable_dir().append("/php-cgi");

// Mongoose options
const char* options[] = {
"document_root", document_root.c_str(),
"listening_ports", listening_ports.c_str(),
"index_files", "index.html,index.php", // @TODO from settings.json
"cgi_interpreter", cgi_interpreter.c_str(),
"cgi_pattern", "**.php$", // @TODO from settings.json
"cgi_environment", cgi_env.c_str(),
"404_handler", "/pretty-urls.php", // @TODO from settings.json
"hide_files_patterns", "", // @TODO from settings.json
NULL
};

// Start mongoose
mg_callbacks callbacks = {0};
callbacks.log_message = &mongoose_log_message;
callbacks.end_request = &mongoose_end_request;
g_mongoose_context = mg_start(&callbacks, NULL, options);
if (g_mongoose_context == NULL) {
LOG(ERROR) << "mg_start() failed";
return false;
}

// When port was set to 0 then a random free port was assigned
// by OS.
int port = mg_get_listening_port(g_mongoose_context);
std::stringstream port_ss;
port_ss << port;
g_mongoose_port = port_ss.str();
if (g_mongoose_ip_address == "*") {
g_mongoose_url = "http://127.0.0.1:" + port_ss.str() + "/";
} else {
g_mongoose_ip_address = g_mongoose_ip_address;
g_mongoose_url = "http://" + g_mongoose_ip_address + ":"
+ g_mongoose_port + "/";
}
LOG(INFO) << "Mongoose url: " << g_mongoose_url;

return true;
}

void MongooseStop() {
// Don't call mg_stop(), as there were issues in the past
// with doing so. It is not necessary to stop mongoose server,
// as this is done only when application quits and mongoose
// server will automatically stop when application quits.
}

std::string MongooseGetPort() {
return g_mongoose_port;
}

std::string MongooseGetIpAddress() {
return g_mongoose_ip_address;
}

std::string MongooseGetUrl() {
return g_mongoose_url;
}
11 changes: 11 additions & 0 deletions src/mongoose_server.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2018 PHP Desktop, see the Authors file.
// All rights reserved. Licensed under BSD 3-clause license.
// Project website: https://github.com/cztomczak/phpdesktop

#include <string>

bool MongooseStart();
void MongooseStop();
std::string MongooseGetPort();
std::string MongooseGetIpAddress();
std::string MongooseGetUrl();
34 changes: 34 additions & 0 deletions src/php.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
; Date
date.timezone=Europe/Berlin

; Errors
error_reporting=E_ALL
display_errors=On
display_startup_errors=On
log_errors=Off
report_memleaks=On
report_zend_debug=On

; General
short_open_tag=On
ignore_user_abort=Off
implicit_flush=Off
output_buffering=0
default_charset = "UTF-8"

; Execution time
max_execution_time=30

; Memory
memory_limit=128M

; File uploads
; "post_max_size" must be equal or bigger than "upload_max_filesize"
max_file_uploads=20
upload_max_filesize=2048M
post_max_size=2048M

; Smtp server is not included with phpdesktop
SMTP=127.0.0.1
smtp_port=25

Loading

0 comments on commit 2f73d49

Please sign in to comment.