Skip to content

Commit 2f73d49

Browse files
committed
Embed Mongoose server and PHP CGI (#221)
PHP Desktop for Linux now displays index.php with phpinfo().
1 parent b927470 commit 2f73d49

File tree

11 files changed

+300
-7
lines changed

11 files changed

+300
-7
lines changed

Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ CCFLAGS += $(shell pkg-config --cflags glib-2.0 gtk+-3.0)
77

88
CFLAGS_OPTIMIZE = -O3 -fvisibility=hidden
99

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

1313
OBJS=\
1414
src/main.o \
1515
src/app.o \
1616
src/client_handler.o \
17+
src/mongoose.o \
18+
src/mongoose_server.o \
19+
src/utils.o \
1720

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

39+
%.o : %.c
40+
+gcc -c -o $@ -MD -MP -MF $@.deps -g -std=c99 -O2 -W -Wall -Werror -pedantic -pthread -pipe $<
41+
3642
$(TARGET): $(OBJS)
3743
+$(CC) $(CCFLAGS) $(CFLAGS_OPTIMIZE) -o $@ $(OBJS) $(LDFLAGS)
3844

build.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ make -R -f Makefile "$@"
2424
rc=$?;
2525
if [[ ${rc} = 0 ]]; then
2626
echo "OK phpdesktop was built";
27+
cp src/php.ini build/bin/
28+
if [[ -d build/bin/www ]]; then
29+
rm -r build/bin/www
30+
fi
31+
cp -r src/www/ build/bin/
2732
./build/bin/phpdesktop
2833
rm -r blob_storage/
2934
rm -r GPUCache/

src/main.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "app.h"
66
#include "client_handler.h"
7+
#include "utils.h"
8+
#include "mongoose_server.h"
79

810
#include "include/base/cef_logging.h"
911
#include "include/wrapper/cef_helpers.h"
@@ -16,6 +18,8 @@
1618
#include <cstring>
1719
#include <cerrno>
1820

21+
std::string g_cgi_env_from_argv = "";
22+
1923

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

3539
int main(int argc, char **argv) {
40+
LOG(INFO) << "Executable directory: " << executable_dir();
41+
42+
// Passing ENV variables to PHP using the --cgi-environment
43+
// command line arg passed to app.
44+
if (argv) {
45+
for (int i = 0; i < argc; i++) {
46+
std::string arg = argv[i];
47+
size_t pos = arg.find("=");
48+
if (pos != std::string::npos) {
49+
std::string name = arg.substr(0, pos);
50+
std::string value = arg.substr(pos+1, std::string::npos);
51+
if (name == "--cgi-environment" && value.length()) {
52+
g_cgi_env_from_argv.assign(value);
53+
}
54+
}
55+
}
56+
}
57+
3658
// Create a copy of |argv| on Linux because Chromium mangles the value
3759
// internally (see CEF issue #620).
3860
CefScopedArgArray scoped_arg_array(argc, argv);
@@ -74,6 +96,15 @@ int main(int argc, char **argv) {
7496
return exit_code;
7597
}
7698

99+
// Single instance application
100+
// @TODO
101+
102+
// Main window title
103+
// @TODO from settings.json
104+
105+
// Start Mongoose server
106+
MongooseStart();
107+
77108
// Install xlib error handlers so that the application won't be terminated
78109
// on non-fatal errors. X11 errors appearing in debug logs usually can be
79110
// ignored.
@@ -83,8 +114,12 @@ int main(int argc, char **argv) {
83114
// Specify CEF global settings here.
84115
CefSettings settings;
85116
settings.no_sandbox = true;
86-
CefString( &settings.log_file ) = "debug.log";
87-
settings.log_severity = LOGSEVERITY_INFO;
117+
CefString( &settings.log_file ) = "debug.log"; // @TODO from settings.json
118+
settings.log_severity = LOGSEVERITY_INFO; // @TODO from settings.json
119+
// @TODO cache_path settings.json option
120+
121+
// Remote debugging port
122+
// @todo from settings.json
88123

89124
// App implements application-level callbacks for the browser
90125
// process.
@@ -113,11 +148,14 @@ int main(int argc, char **argv) {
113148
CefBrowserHost::CreateBrowserSync(
114149
window_info,
115150
ClientHandler::GetInstance(),
116-
"https://www.google.com/",
151+
MongooseGetUrl(),
117152
browser_settings,
118153
NULL);
119154

120155
CefRunMessageLoop();
156+
157+
LOG(INFO) << "Stop Mongoose server";
158+
MongooseStop();
121159

122160
LOG(INFO) << "Shutdown CEF";
123161
CefShutdown();

src/mongoose.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,9 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
14711471
(void) execle(prog, prog, NULL, envp);
14721472
cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
14731473
} else {
1474+
// char prog_abspath[PATH_MAX];
1475+
// strcpy(prog_abspath, dir);
1476+
// strcat(prog_abspath, prog);
14741477
(void) execle(interp, interp, prog, NULL, envp);
14751478
cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
14761479
strerror(ERRNO));
@@ -1832,6 +1835,7 @@ static void support_path_info_for_cgi_scripts(
18321835
struct mg_connection *conn, char *buf,
18331836
size_t buf_len, struct file *filep) {
18341837
char *p;
1838+
if (buf_len) {} // unused paramter during compilation
18351839
// Support PATH_INFO for CGI scripts.
18361840
for (p = buf + strlen(buf); p > buf + 1; p--) {
18371841
if (*p == '/') {
@@ -3387,8 +3391,8 @@ static void prepare_cgi_environment(struct mg_connection *conn,
33873391
if (prog2[i] == '/') {
33883392
prog2[i] = '\\';
33893393
}
3390-
#endif
33913394
}
3395+
#endif
33923396

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

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

55205525
void mg_stop_immediately(struct mg_context *ctx) {
5526+
if (ctx) {} // unused parameter warning
55215527
// Stopping Mongoose and freeing resources will hang when
55225528
// used with IE webbrowser control. It seems that IE is not
55235529
// freeing reources properly, it does it with some delay.

src/mongoose_server.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Copyright (c) 2018 PHP Desktop, see the Authors file.
2+
// All rights reserved. Licensed under BSD 3-clause license.
3+
// Project website: https://github.com/cztomczak/phpdesktop
4+
5+
#include "mongoose.h"
6+
#include "utils.h"
7+
#include "version.h"
8+
#include "include/base/cef_logging.h"
9+
10+
std::string g_mongoose_port = "0"; // @TODO from settings.json
11+
std::string g_mongoose_ip_address = "127.0.0.1"; // @TODO from settings.json
12+
std::string g_mongoose_url = "";
13+
14+
struct mg_context* g_mongoose_context = 0;
15+
extern std::string g_cgi_env_from_argv;
16+
17+
static int mongoose_log_message(const struct mg_connection* conn,
18+
const char *message) {
19+
// Called when mongoose is about to log a message. If callback returns
20+
// non-zero, mongoose does not log anything.
21+
LOG(WARNING) << message;
22+
return 0;
23+
}
24+
25+
static void mongoose_end_request(const struct mg_connection* conn,
26+
int reply_status_code) {
27+
// Called when mongoose has finished processing request.
28+
mg_request_info* request = mg_get_request_info(
29+
const_cast<mg_connection*>(conn));
30+
std::string message;
31+
message.append(request->request_method);
32+
message.append(" ");
33+
std::stringstream ss;
34+
ss << reply_status_code;
35+
message.append(ss.str());
36+
message.append(" ");
37+
message.append(request->uri);
38+
if (request->query_string) {
39+
message.append("?");
40+
message.append(request->query_string);
41+
}
42+
LOG(INFO) << message;
43+
}
44+
45+
bool MongooseStart() {
46+
LOG(INFO) << "Start Mongoose server";
47+
48+
// Temp directory
49+
std::string cgi_temp_dir = "/tmp";
50+
// @TODO load cgi_temp_dir from settings.json
51+
char const* tmp = getenv("TMP");
52+
if (tmp != NULL) {
53+
cgi_temp_dir.assign(tmp);
54+
} else {
55+
char const* temp = getenv("TEMP");
56+
if (temp != NULL) {
57+
cgi_temp_dir.assign(temp);
58+
} else {
59+
char const* tmpdir = getenv("TMPDIR");
60+
if (tmpdir != NULL) {
61+
cgi_temp_dir.assign(tmpdir);
62+
}
63+
}
64+
}
65+
66+
// CGI environment variables
67+
std::string cgi_env = "";
68+
cgi_env.append("TMP=").append(cgi_temp_dir).append(",");
69+
cgi_env.append("TEMP=").append(cgi_temp_dir).append(",");
70+
cgi_env.append("TMPDIR=").append(cgi_temp_dir).append(",");
71+
if (g_mongoose_ip_address != "*") {
72+
cgi_env.append("SERVER_NAME=").append(g_mongoose_ip_address)
73+
.append(",");
74+
}
75+
cgi_env.append("PHPDESKTOP_VERSION=").append(PHPDESKTOP_VERSION);
76+
if (g_cgi_env_from_argv.length()) {
77+
cgi_env.append(",").append(g_cgi_env_from_argv);
78+
}
79+
LOG(INFO) << "CGI environment variables set: " << cgi_env;
80+
81+
// Document root
82+
std::string document_root = executable_dir().append("/www");
83+
LOG(INFO) << "document_root=" << document_root;
84+
85+
// Listening ports
86+
// @TODO from settings.json
87+
std::string listening_ports;
88+
if (g_mongoose_ip_address == "*") {
89+
listening_ports = g_mongoose_port;
90+
} else {
91+
listening_ports = g_mongoose_ip_address + ":" + g_mongoose_port;
92+
}
93+
94+
// CGI interpreter
95+
std::string cgi_interpreter = executable_dir().append("/php-cgi");
96+
97+
// Mongoose options
98+
const char* options[] = {
99+
"document_root", document_root.c_str(),
100+
"listening_ports", listening_ports.c_str(),
101+
"index_files", "index.html,index.php", // @TODO from settings.json
102+
"cgi_interpreter", cgi_interpreter.c_str(),
103+
"cgi_pattern", "**.php$", // @TODO from settings.json
104+
"cgi_environment", cgi_env.c_str(),
105+
"404_handler", "/pretty-urls.php", // @TODO from settings.json
106+
"hide_files_patterns", "", // @TODO from settings.json
107+
NULL
108+
};
109+
110+
// Start mongoose
111+
mg_callbacks callbacks = {0};
112+
callbacks.log_message = &mongoose_log_message;
113+
callbacks.end_request = &mongoose_end_request;
114+
g_mongoose_context = mg_start(&callbacks, NULL, options);
115+
if (g_mongoose_context == NULL) {
116+
LOG(ERROR) << "mg_start() failed";
117+
return false;
118+
}
119+
120+
// When port was set to 0 then a random free port was assigned
121+
// by OS.
122+
int port = mg_get_listening_port(g_mongoose_context);
123+
std::stringstream port_ss;
124+
port_ss << port;
125+
g_mongoose_port = port_ss.str();
126+
if (g_mongoose_ip_address == "*") {
127+
g_mongoose_url = "http://127.0.0.1:" + port_ss.str() + "/";
128+
} else {
129+
g_mongoose_ip_address = g_mongoose_ip_address;
130+
g_mongoose_url = "http://" + g_mongoose_ip_address + ":"
131+
+ g_mongoose_port + "/";
132+
}
133+
LOG(INFO) << "Mongoose url: " << g_mongoose_url;
134+
135+
return true;
136+
}
137+
138+
void MongooseStop() {
139+
// Don't call mg_stop(), as there were issues in the past
140+
// with doing so. It is not necessary to stop mongoose server,
141+
// as this is done only when application quits and mongoose
142+
// server will automatically stop when application quits.
143+
}
144+
145+
std::string MongooseGetPort() {
146+
return g_mongoose_port;
147+
}
148+
149+
std::string MongooseGetIpAddress() {
150+
return g_mongoose_ip_address;
151+
}
152+
153+
std::string MongooseGetUrl() {
154+
return g_mongoose_url;
155+
}

src/mongoose_server.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) 2018 PHP Desktop, see the Authors file.
2+
// All rights reserved. Licensed under BSD 3-clause license.
3+
// Project website: https://github.com/cztomczak/phpdesktop
4+
5+
#include <string>
6+
7+
bool MongooseStart();
8+
void MongooseStop();
9+
std::string MongooseGetPort();
10+
std::string MongooseGetIpAddress();
11+
std::string MongooseGetUrl();

src/php.ini

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
; Date
2+
date.timezone=Europe/Berlin
3+
4+
; Errors
5+
error_reporting=E_ALL
6+
display_errors=On
7+
display_startup_errors=On
8+
log_errors=Off
9+
report_memleaks=On
10+
report_zend_debug=On
11+
12+
; General
13+
short_open_tag=On
14+
ignore_user_abort=Off
15+
implicit_flush=Off
16+
output_buffering=0
17+
default_charset = "UTF-8"
18+
19+
; Execution time
20+
max_execution_time=30
21+
22+
; Memory
23+
memory_limit=128M
24+
25+
; File uploads
26+
; "post_max_size" must be equal or bigger than "upload_max_filesize"
27+
max_file_uploads=20
28+
upload_max_filesize=2048M
29+
post_max_size=2048M
30+
31+
; Smtp server is not included with phpdesktop
32+
SMTP=127.0.0.1
33+
smtp_port=25
34+

0 commit comments

Comments
 (0)