Coder Social home page Coder Social logo

cesanta / mongoose Goto Github PK

View Code? Open in Web Editor NEW
10.6K 459.0 2.6K 30.95 MB

Embedded Web Server

Home Page: https://mongoose.ws

License: Other

Makefile 0.87% C 90.15% HTML 0.05% C++ 5.81% Shell 0.24% Batchfile 0.02% JavaScript 2.85%
websocket mqtt embedded webserver web-server iot http tcp udp tcpip

mongoose's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mongoose's Issues

Denial of service

Specifying a large negative number for Content-Length makes Mongoose crash. I tested this with mongoose-3.1.exe

The following request consistently crashes the server:

GET /index.html HTTP/1.0
Content-Length: -268435455700

bug on read_websocket, when content_len >=126

static void read_websocket(struct mg_connection *conn)
{
unsigned char *mask, *buf = (unsigned char *) conn->buf + conn->request_len;
int n, len, mask_len, body_len, discard_len;

    for (;;) {
            if ((body_len = conn->data_len - conn->request_len) >= 2) {
                    len = buf[1] & 127;
                    mask_len = buf[1] & 128 ? 4 : 0;
                    if (len < 126) {
                            conn->content_len = 2 + mask_len + len;
                            mask = buf + 2;
                    } else if (len == 126 && body_len >= 4) {
                            //conn->content_len = 2 + mask_len + ((((int) buf[2]) << 8) + buf[3]); 
                            conn->content_len = 4 + mask_len + ((((int) buf[2]) << 8) + buf[3]); 
                            mask = buf + 4;
                    } else if (body_len >= 10) {
                            //conn->content_len = 2 + mask_len +
                            conn->content_len = 10 + mask_len +
                                                (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) |
                                                htonl(* (uint32_t *) &buf[6]);
                            mask = buf + 10;
                    }
            }

mg_printf - return -1 if strlen(fmt) > MG_BUF_LEN

http://msdn.microsoft.com/en-us/library/1kt27hek%28v=vs.80%29.aspx
vsnprintf,_vsnprintf, and _vsnwprintf return the number of characters written if the number of characters to write is less than or equal to count; if the number of characters to write is greater than count, these functions return -1 indicating that output has been truncated. The return value does not include the terminating null, if one is written.

Test code:

include <stdio.h>

include <stdarg.h>

int mg_printf(const char *fmt, ...) {
char mem[10];
int len;
va_list ap;
// Print in a local buffer first, hoping that it is large enough to
// hold the whole message
va_start(ap, fmt);
len = vsnprintf(mem, sizeof(mem), fmt, ap);
va_end(ap);
printf("len = %d", len);
return len;
}

int main()
{
mg_printf(0,"%d - long stringlong stringlong stringlong string ",123);
return 0;
}

stdout:
len = -1

Temp fix:

int mg_printf_dynamic(struct mg_connection *conn, const int len_helper, const char *fmt, ...)
{
va_list ap;
int len = -1;
int l_fly_size = len_helper;
char *l_fly_buf = (char *)malloc(l_fly_size);
if(l_fly_buf)
{
l_fly_buf[0] = 0;
va_start(ap, fmt);
while(_vsnprintf(l_fly_buf, l_fly_size, fmt, ap) == -1){
free(l_fly_buf);
l_fly_size *= 2;
l_fly_buf = (char *)malloc(l_fly_size);
if(!l_fly_buf)
return -1;
l_fly_buf[0] = 0;
}
va_end(ap);
len = mg_write(conn, l_fly_buf, (size_t) l_fly_size);
free(l_fly_buf);
}
return len;
}

Issue in windows for cgi index

Hello Sergey,

Here's the solution I hope it resolves this issue. if you define index.php as an index in a webdirectory you get a file not found error.

Am pasting the solution here ... I just upgraded my systems at home and have not installed github. Hope this helps ... great peace of code ... and hope I can contribute ...

Jojo Kahanding

// This is the heart of the Mongoose's logic.
// This function is called when the request is read, parsed and validated,
// and Mongoose must decide what action to take: serve a file, or
// a directory, or call embedded function, etcetera.
static void handle_request(struct mg_connection *conn) {
struct mg_request_info *ri = &conn->request_info;
char path[PATH_MAX];
int stat_result, uri_len;
struct mgstat st;

if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
* conn->request_info.query_string++ = '\0';
}
uri_len = strlen(ri->uri);
url_decode(ri->uri, (size_t)uri_len, ri->uri, (size_t)(uri_len + 1), 0);
remove_double_dots_and_double_slashes(ri->uri);
stat_result = convert_uri_to_file_name(conn, path, sizeof(path), &st);

DEBUG_TRACE(("%s", ri->uri));
if (!check_authorization(conn, path)) {
send_authorization_request(conn);
} else if (call_user(conn, MG_NEW_REQUEST) != NULL) {
// Do nothing, callback has served the request
} else if (!strcmp(ri->request_method, "OPTIONS")) {
send_options(conn);
} else if (strstr(path, PASSWORDS_FILE_NAME)) {
// Do not allow to view passwords files
send_http_error(conn, 403, "Forbidden", "Access Forbidden");
} else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
send_http_error(conn, 404, "Not Found", "Not Found");
} else if ((!strcmp(ri->request_method, "PUT") ||
!strcmp(ri->request_method, "DELETE")) &&
(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ||
!is_authorized_for_put(conn))) {
send_authorization_request(conn);
} else if (!strcmp(ri->request_method, "PUT")) {
put_file(conn, path);
} else if (!strcmp(ri->request_method, "DELETE")) {
if (mg_remove(path) == 0) {
send_http_error(conn, 200, "OK", "");
} else {
send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
strerror(ERRNO));
}
} else if (stat_result != 0) {
send_http_error(conn, 404, "Not Found", "%s", "File not found");
} else if (st.is_directory && ri->uri[uri_len - 1] != '/') {
(void) mg_printf(conn,
"HTTP/1.1 301 Moved Permanently\r\n"
"Location: %s/\r\n\r\n", ri->uri);
} else if (!strcmp(ri->request_method, "PROPFIND")) {
handle_propfind(conn, path, &st);
} else if (st.is_directory &&
!substitute_index_file(conn, path, sizeof(path), &st)) {
if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
handle_directory_request(conn, path);
} else {
send_http_error(conn, 403, "Directory Listing Denied",
"Directory listing denied");
}

if !defined(NO_CGI)

} else if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
strlen(conn->ctx->config[CGI_EXTENSIONS]),
path) > 0) {
if (strcmp(ri->request_method, "POST") &&
strcmp(ri->request_method, "GET")) {
send_http_error(conn, 501, "Not Implemented",
"Method %s is not implemented", ri->request_method);
} else {
// ==================================================================
// BEGIN Revision <<<ISSUE:"windows cgi index">>>
// <<<Author: Jojo Kahanding>>>
// <<<TIME:August 16, 2012 at 14:53 >>>
// COMMENTS: ""
//

if 1

/* NEW CODE =========================================================*/

ifdef _WIN32

    char *head = path;

    while (*head)
    {
        if (*head == '\\')
            *head = '/';
        head++;
    }

endif

/* =================================================================*/

else

/* OLD CODE =========================================================*/

/* =================================================================*/

endif

// END Revision <<ISSUE:"">>
/* =================================================================*/
handle_cgi_request(conn, path);
}

endif // !NO_CGI

} else if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
strlen(conn->ctx->config[SSI_EXTENSIONS]),
path) > 0) {
handle_ssi_file_request(conn, path);
} else if (is_not_modified(conn, &st)) {
send_http_error(conn, 304, "Not Modified", "");
} else {
handle_file_request(conn, path, &st);
}
}

mg_request_info retrieved from mg_get_request_info() should not be const

Suppose my callback function handles a MG_NEW_REQUEST event by returning a 304 status. How does the request_info->status_code get updated if the request_info is const? I know it can be cast away. But that isn't elegant or proper coding. The problem I have is I need the status code in the MG_REQUEST_COMPLETE event. Likewise, making the mg_request_info const, makes the user_data pointer const as well. Again, it can be cast away. But that's still not elegant.

I'm not sure there is a simple solution. I just wanted to point out an issue I've been having.

Windows build doesn't exit cleanly when terminated externaly

When using taskkill or sending the WM_CLOSE message:

  1. WinMain doesn't always exit properly (GetMessage can return -1 on error).
  2. No cleanups are performed.

Here's a patch which fixes both issues:

--- valenok-mongoose-375950f/main.c Wed Aug 15 16:05:46 2012
+++ valenok-mongoose-375950f/main.c Thu Aug 16 15:28:36 2012
@@ -438,14 +438,19 @@
           SetForegroundWindow(hWnd);
           TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL);
           PostMessage(hWnd, WM_NULL, 0, 0);
           DestroyMenu(hMenu);
           break;
       }
       break;
+    case WM_CLOSE:
+      mg_stop(ctx);
+      Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
+      PostQuitMessage(0);
+      return 0; // We've just sent our own quit message, with proper hwnd.
   }
 
   return DefWindowProc(hWnd, msg, wParam, lParam);
 }
 
 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) {
   WNDCLASS cls;
@@ -469,18 +474,19 @@
   TrayIcon.hIcon = LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_ICON),
                              IMAGE_ICON, 16, 16, 0);
   TrayIcon.hWnd = hWnd;
   snprintf(TrayIcon.szTip, sizeof(TrayIcon.szTip), "%s", server_name);
   TrayIcon.uCallbackMessage = WM_USER;
   Shell_NotifyIcon(NIM_ADD, &TrayIcon);
 
-  while (GetMessage(&msg, hWnd, 0, 0)) {
+  while (GetMessage(&msg, hWnd, 0, 0) > 0) {
     TranslateMessage(&msg);
     DispatchMessage(&msg);
   }
+  return msg.wParam;
 }
 #else
 int main(int argc, char *argv[]) {
   init_server_name();
   start_mongoose(argc, argv);
   printf("%s started on port(s) %s with web root [%s]\n",
          server_name, mg_get_option(ctx, "listening_ports"),

mg_printf not printing strings, larger then MG_BUF_LEN

Hi.
I noticed that Visual Studio 2010 has slightly different implementation of vsnprintf, that returns -1 if the string is larger then provided buffer.
Because of this, mg_printf fails to print large messages.

Relevant code (mongoose.c:1560):

...
  va_start(ap, fmt);
  len = vsnprintf(mem, sizeof(mem), fmt, ap);
  va_end(ap);

  if (len == 0) {
    // Do nothing. mg_printf(conn, "%s", "") was called.
  } else if (len < 0) {
    // vsnprintf() error, give up
    len = -1;
    cry(conn, "%s(%s, ...): vsnprintf() error", __func__, fmt);
  } else if (len > (int) sizeof(mem) && (buf = (char *) malloc(len + 1)) != NULL) {
    // Local buffer is not large enough, allocate big buffer on heap
...

Worker threads can get stuck if client does not gracefully close cnxn

We've seen an issue where worker threads can get stuck in wait_until_socket_is_readable in the pull call in close_connection. The problem is that we had some clients not correctly shutting down the connection and therefore select never returns an error on that socket (and also never marks it as readable).

Eventually, all worker threads get stuck, and Mongoose can no longer serve requests. On some kernels tcp_fin_timeout should timeout sockets that are stuck in FIN_WAIT2, but it doesn't seem to work like that.

Regardless, it seems like it would be better if Mongoose was more robust to badly behaved clients. It's not totally clear what the right answer is - the easy one is doing a timeout inside the select loop but I don't know how correct that would be.

(We're on Centos 6.2).

Connecting using https to non-ssl port causes mongoose to hang

If mongoose is configure to serve both http and https, then connecting to the http port using https in the browser causes mongoose to no longer properly serve http or https connections.

For example, if mongoose is set up to serve http on port 9001 and https on 443:
http://localhost:9001 ==> works fine
https://localhost:443 ==> works fine
https://localhost:9001 ==> returns "The connection was interrupted"
From this point on connections to either http or http returns: "The connection was reset".
http://localhost:9001 ==> returns: "The connection was reset".

I traced the problem a little. It appears that the buf in the call to get_request_len() from read_request() gets filled with encrypted data that can't be read, and it's never removed.

Would it make sense to add code to clear conn->buf if request_len is set to -1 after the call to read_request() in function process_new_connection()?

Mongoose 3.2 works, 3.3 doesn't, same config file.

I receive the error "No input file specified."

Here's my config file, without the comments:

cgi_interpreter php/php-cgi.exe
authentication_domain localhost
error_log_file error_log.txt
index_files index.html,index.htm,index.cgi,index.php
listening_ports 127.0.0.1:80
document_root www

My directory structure is like this:

.
mongoose-3.3.exe
mongoose-3.2.exe
mongoose.conf
php/
    php.exe
    php_cgi.exe
    php.ini
    a bunch of .dll files
www/
    index.php

I am using all relative paths so that it's portable between the 3 systems I use (synced over Dropbox). PHP version is the latest, 5.4.0 from windows.php.net.

I have followed the direction in the wiki and made sure that no doc_root is in php.ini, in fact my PHP.ini is quite short:

date.timezone="America/New_York"
upload_max_filesize=8M
error_reporting=-1
extension_dir="."
extension=php_curl.dll
extension=php_fileinfo.dll
... and so on, just more extensions that load fine in 3.2

When I run mongoose 3.2, this config and directory structure works fine. I've messed around with the cgi.* directives in php.ini but with no luck. For now my solution has been to use 3.2, which is fine but I'd like to not continue using an old version eternally.

Any help would be much appreciated, I think I've tried everything I can on my own to resolve this. Thanks.

Allow service installation and uninstall from command line

It seems that there is currently no option to install/uninstall the service from the command line.

On Windows, using sc.exe doesn't work for some reason.
I tried the following, to replicate the exact settings that Mongoose uses to install itself as a service:

:: Install the service
> sc create "Mongoose" start= auto DisplayName= "Mongoose" binPath= "E:\PhoenixServer\helpserver\mongo
ose.exe --"
:: Change its description
> sc description mongoose "Mongoose web server v. 3.3"

The service is correctly installed, and it correctly starts, but there is no response from the server when browsing files, and no errors are generated (either in the error log or in the Windows event log).
Installing the service from the Mongoose trayicon menu, using the exact same settings, works perfectly.

Issue found on Win8 x64, and Windows Server 2003 x86.

EDIT: using sc.exe actually works, I had an error in my mongoose.conf file that was pointing the document_root to a relative path rather than an absolute path.
I will therefore close this issue.

HEAD request against CGI file yields 501 Not Implemented

I get the expected 200 OK responses from HEAD requests against static files, but requesting https://github.com/jquery/jquery/blob/228ab3ddae527f72cc3122a1c6115d7718bcfd57/test/data/ajax/echo/index.php in a local run of the jQuery test suite yields 501 Not Implemented.

The script is a basic PHP response generator, and in this case sends the following to mongoose:

HTTP/1.1 200 
X-Powered-By: PHP/5.3.10-1ubuntu3.4
Content-Type: text/plain

head request

Feature request! please add support for serving web root from a zip file .

Hi there, I has embed mongoose for my app to provide a web interface. Too many web files in the distribution package is not a good idea and it also has security issues, so i hope that mongoose could serve web pages from a single zip file. Please add this feature.

thanks for your code again.

solosky

sync wiki - pull from GerHobbelt/mongoose-vanilla

Okay, synchronizing wiki's is going to take a few git commands to accomplish.

First of all, here's the 'original': https://github.com/GerHobbelt/mongoose-vanilla
Notice that that one has a wiki (go to 'admin' and enable it; the wiki will be a separate git repository, as mentioned in the 'git access' tab in the wiki section, once you've got it enabled -- a basic welcome page will show as 'Home' in the meantime.

The git repo for the mongoose-vanilla wiki contains the entire hg history from googlecode (as mentioned in email I had a mirror from 25/jul/2012, luckily) plus a series of edits by me to make it 'markdown' format. It's done fast, so I'm sure there's enough points to nitpick for anyone, but now we have a wiki back up online)

How to pull this into your (valenok) wiki repo.
Unfortunately, github greatness stops at 'pull requests for wikis', so we have to do it manually. Sorry for that.

As described in your wiki section tab 'git access' you'll have SSH git access for your own wiki repo. For me, that would be:
[email protected]:GerHobbelt/mongoose-vanilla.wiki.git
so yours would be:
[email protected]:valenok/mongoose.wiki.git

on your local machine, in a place outside any other git repo (to keep things clean for that one), clone it as
git clone [email protected]:valenok/mongoose.wiki.git
then
cd mongoose.wiki
then
git remote add gerhobbelt-wiki git://github.com/GerHobbelt/mongoose-vanilla.wiki.git
git pull --all

When you use tortoiseGit like I do, you only see this 'unrelated remote' when you tick the checkbox 'All Branches' in TortoiseGit when you 'Show Log' via the context menu of Windows explorer inside that mongoose.wiki dir.
Otherwise, it's just the command
git merge remotes/gerhobbelt-wiki/master
when you use this command to merge, verify it, because this was written from the top of my head!

The merge will show a single conflict for the Home.md file as your own will clash with mine, according to git (and it is right); merge 'using theirs' to force git to use the Home.md provided by that remote repo.
Then
git commit -a
the merge and
git push --all
to update your own wiki; it should now show the same content as my mongoose-vanilla project wiki.

(When you do this merging in Tortoise, what I generally do is first merge the oldest commit, which will show a conflict here, then 'use theirs' resolve that one, then go to the last commit (HEAD) and merge that. No real difference, just taste/habit.)

thread stack size limitations (ref. TODO note)

pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5);

... does not work because (sizeof(struct mg_connection) * 5) is less than PTHREAD_STACK_MIN, so there is not even enough stack space for creating the thread.

My advice would be to not limit the stack size at all - the default is usually well chosen.

Thank you for this project!

Websockets does not work for big endian machines (e.g. ppc)

The websockets example works on my x86 machine (32 bit linux), but not when mongoose runs on a ppc (big endian). This patch fixes the problem for me (gcc 4.6):

--- a/external/mongoose/mongoose.c
+++ b/external/mongoose/mongoose.c
@@ -3593,13 +3593,13 @@ static void handle_propfind(struct mg_connection *conn, 
 #include "solarisfixes.h"
 #endif
 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
-#if BYTE_ORDER == LITTLE_ENDIAN
+#if !(defined __BYTE_ORDER)
+#error "Endianness not defined!"
+#elif (__BYTE_ORDER == __LITTLE_ENDIAN)
 #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
     |(rol(block->l[i],8)&0x00FF00FF))
-#elif BYTE_ORDER == BIG_ENDIAN
+#elif (__BYTE_ORDER == __BIG_ENDIAN)^M
 #define blk0(i) block->l[i]
-#else
-#error "Endianness not defined!"
 #endif
 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
     ^block->l[(i+2)&15]^block->l[i&15],1))

test/\/a.txt

Hi

TortoiseGit, at least on windows, is permanently indicating a change that test//a.txt has been deleted. But it cannot be resolved/reverted because (my assumption) \ is no valid directory name on windows.

What is the purpose of this directory and the file? Is there a workaround for windows users?

Thanks,
Simon

read_websocket function failed when body_len > 126

Description:

I test websocket with examples/websocket_html_root/index.html. If I send data it's length less than 126, websocket will receive all data. But if I send data it's length greater than 126, the data websocket received is less 2 bytes than sended.

Suggested fix:

diff --git a/mongoose.c b/mongoose.c
index 21a9aba..ba7a38f 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -3774,10 +3774,10 @@ static void read_websocket(struct mg_connection *conn) {
         conn->content_len = 2 + mask_len + len;
         mask = buf + 2;
       } else if (len == 126 && body_len >= 4) {
 -        conn->content_len = 2 + mask_len + ((((int) buf[2]) << 8) + buf[3]);
 +        conn->content_len = 2 + 2 + mask_len + ((((int) buf[2]) << 8) + buf[3]);
         mask = buf + 4;
       } else if (body_len >= 10) {
 -        conn->content_len = 2 + mask_len +
 +        conn->content_len = 2 + 8 + mask_len +
           (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) |
           htonl(* (uint32_t *) &buf[6]);
         mask = buf + 10;

broken or invalid cgi causes app exception on WinXP

Traced the error, the exception stopped in
handle_cgi_request() in mongoose.c.

I believe that the fd_stdin[0] , fd_stdout[1] will be closed twice after spawn_process() is called. Because when this function fails, process goes to done without resetting the fd_stdin.

I fixed this by:

if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
send_http_error(conn, 500, http_500_error,
"Cannot create CGI pipe: %s", strerror(ERRNO));
goto done;
} else if ((pid = spawn_process(conn, p, blk.buf, blk.vars,
fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) {
send_http_error(conn, 500, http_500_error,
"Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
fd_stdin[0] = fd_stdout[1] = -1;//<============add this code here to avoid exception.
goto done;
}

// spawn_process() must close those!
// If we don't mark them as closed, close() attempt before
// return from this function throws an exception on Windows.
// Windows does not like when closed descriptor is closed again.
fd_stdin[0] = fd_stdout[1] = -1;

Access to POST body

I'm trying to figure out how to access the post body in a request with mongoose. I can see the data in mg_connection but that is defined in the c file so I'm guessing I'm not supposed to access it via there. How am I supposed to access it?

DAV Requests fail with in .htpasswd protected directories

Issue found in v.3.3

Description:

I have the following setup: Mongoose is running with a put_delete_passwords_file password set. When trying to PUT files into a directory that is .htpasswd protected, authentication always fails.

I added some debugging code and found the cause of the issue to be the following:
In order to authorize the request, mongoose tests both the put_delete_passwords_file and the local directories .htpasswd file using the same credentials. The authorize() functions always fails if the credentials in those files are not identical.

Suggested fix:

The first call to authorized is issued in check_authorization (propably due to an OPTIONS req) and succeeds. Then is_authorized_for_put is called by handle_request which reuses the same credentials as check_authorization and naturally fails.

A suggested fix would be to retain a separate structure for DAV write authorizations in handle_request, thus allowing is_authorized_for_put to use separate credentials than check_authorization.

Workaround:

Add the put_delete_passwords_file credentials to all .htpasswd files protecting the directories in order to get PUT/DELETE access to those directories.

Output of own debug code inserted into mongoose.c:

--- Initial directory listing (against .htpasswd) ---
DBG: handle_request: need AUTH for general Req
DBG: authorize: checking fd: 144296864
DGB: authorize : Checking user ichrispa against ichrispa
DBG: check_password: uri: /examples/; nonce: 1352671403; cnconce: abd683fdb2975385ac72deb1edb03ede; response: 520a2e91d8490c44e637d080bc1636d4; nc: 00000001; ha1: 7eb13f090655204ef26a9c7cbd4b3c3b; qop: auth
...check succeeded

--- Auth for DAV PUT Request ---
DBG: authorize: checking fd: 144296864 (==put_delete_passwords_file)
DGB: authorize : Checking user ichrispa against ichrispa
DBG: check_password: uri: /examples/Diagram2.dia; nonce: 1352671403; cnconce: abd683fdb2975385ac72deb1edb03ede; response: e6486435b31a9d41726f8e096c72b4bf; nc: 00000002; ha1: 7eb13f090655204ef26a9c7cbd4b3c3b; qop: auth
...check succeeded
DBG: authorize: checking fd: 144296864 (== .htpasswd)
DGB: authorize : Checking user ichrispa against ichrispa
DBG: check_password: uri: /examples/Diagram2.dia; nonce: 1352671403; cnconce: abd683fdb2975385ac72deb1edb03ede; response: e6486435b31a9d41726f8e096c72b4bf; nc: 00000002; ha1: ebbf145890b0683b67fcd206a85ed721; qop: auth
...check failed
DBG: handle_request: Need AUTH for DAV PUT req

Why does not support virtual directory in version 3.4

I need use the virtual directory , but it don't support on version 3.4.
I compared the code, It have get_document_root() function that is parsed the virtual directory in 3.0, but 3.4 havn't.

// Mongoose allows to specify multiple directories to serve,
// like /var/www,/~bob=/home/bob. That means that root directory depends on URI.
// This function returns root dir for given URI.
static int get_document_root(const struct mg_connection *conn,
struct vec *document_root) {
const char *root, *uri;
int len_of_matched_uri;
struct vec uri_vec, path_vec;

uri = conn->request_info.uri;
len_of_matched_uri = 0;
root = next_option(conn->ctx->config[DOCUMENT_ROOT], document_root, NULL);

while ((root = next_option(root, &uri_vec, &path_vec)) != NULL) {
if (memcmp(uri, uri_vec.ptr, uri_vec.len) == 0) {
*document_root = path_vec;
len_of_matched_uri = uri_vec.len;
break;
}
}

return len_of_matched_uri;
}

static void convert_uri_to_file_name(struct mg_connection *conn,
const char *uri, char *buf,
size_t buf_len) {
struct vec vec;
int match_len;

match_len = get_document_root(conn, &vec);
mg_snprintf(conn, buf, buf_len, "%.*s%s", vec.len, vec.ptr, uri + match_len);

if defined(_WIN32) && !defined(SYMBIAN32)

change_slashes_to_backslashes(buf);

endif /* _WIN32 */

DEBUG_TRACE(("[%s] -> [%s], [%.*s]", uri, buf, (int) vec.len, vec.ptr));
}

mg_read not workinig on http client connection

Hi,

i encountered a problem, when i initialize a new remote connection ,with 'mg_connect', i found no way to read from this connection, beacuse 'mg_read' always return 0, in the source i found a comment that indicates conn->content_len isn't set properly. Is there any solution to this or any workaround?

Thanks,
Levente

Segmentation fault after update from 3.1 to 3.4

Hello,

I've updated the mongoose version in my project from 3.1 to 3.4
Unfortunately, every time I launch the app and surf to localhost:8085 (I changed the port because another app is already using 8080), I get a error message in the code saying "Segmentation fault (core dumped)".
In the browser (in this case Chrome 19) I get this: "Error 324 (net::ERR_EMPTY_RESPONSE): The server closed the connection without sending any data.".
Any suggestions on what the problem might be?

conditional SSL

In commit e6bb39a the check for 'pem == NULL' was removed in set_ssl_option.
As a result it is no longer possible to have a server that doesn't use SSL, but wasn't compiled with NO_SSL. I don't want to compile with NO_SSL, but I do want to disable SSL for certain applications without then having to redistribute the OpenSSL DLL files.

First line of CGI script is not read properly on Windows when cgi_interpreter is commented out

Hi,

On Windows, when 'cgi_interpreter' is left commented out in the configuration file, the bang line (first line) of a CGI script is not being read or executed properly on Windows. When 'cgi_interpreter' is specified however, the script will run. The same script will run under Apache, so the bang line is correct.

The script will also run under Linux and OS X when 'cgi_interpreter' is left commented out, so this problem is specific to how the first line is read and executed on Windows.

This is the case with any interpreter (Perl, Python, etc...) using Mongoose version 3.3 on Windows XP and 7.

As CGI scripts for different interpreters may be used, it would be very helpful if this was fixed.

Thanks,
Steven

Examples don't `make` on windows (using mingw)

OS=uname;
test "$OS" = Linux && LIBS="-ldl" ;
cc -W -Wall -I.. -pthread -g hello.c ../mongoose.c $LIBS -o hello;
'OS' is not recognized as an internal or external command,
operable program or batch file.
Makefile:4: recipe for target 'all' failed
mingw32-make.exe: *** [all] Error 1

Make mongoose close automatically

Do anyone knows if it possible to make mongoose to close itself when the page automatically opened by mongoose.exe is closed from the browser?

Thanks in advance!

Correction for Solaris compile error?

The current (Sep 06) version of mongoose.c is producing this preprocessor error on Solaris 10.

/usr/include/sys/feature_tests.h:332:2: #error "Compiler or options invalid for pre-UNIX 03 X/Open applications and pre-2001 POSIX applications"

The conditional expression that triggers the error is:

if defined(_STDC_C99) && (defined(__XOPEN_OR_POSIX) && !defined(_XPG6))

The problem comes from the _XPG6 that is defined further above in feature_tests.h.
It is looking at the value of _XOPEN_SOURCE that states which version of X/Open the code complies with.
In mongoose.c, the name is defined but without a value.
By changing it to 600 (i.e. version 6), the error goes away and we get a clean Solaris compile.

define _XOPEN_SOURCE 600 // For flockfile() on Linux

This does no harm on Linux and actually cleans up a warning about the implicit declaration of usleep().

I do not have access to the other supported platforms to determine if this change would need further #ifdefs around it for Windows, etc.

Avoid "vsnprintf() error" when serving responses without a body

Hi, i noticed that
responding to requests with status codes 1xx, 204 or 304 will lead to a cry in mg_printf because of the empty response body.
the following code

mongoose.c:889:

conn->num_bytes_sent += mg_printf(conn, "%s", buf);

will be called with "%s","" in case of one of the above response codes and will generate a call to cry in mg_printf as the resulting length of the vsnprintf'd string will be '0':

mongoose.c:1484:

int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
 char mem[MG_BUF_LEN], *buf = mem;
 int len;
 va_list ap;

 // Print in a local buffer first, hoping that it is large enough to
 // hold the whole message
 va_start(ap, fmt);
 len = vsnprintf(mem, sizeof(mem), fmt, ap);
 va_end(ap);

 if (len <= 0) {
 // vsnprintf() error, give up
 len = -1;
 cry(conn, "%s(%s, ...): vsnprintf() error", __func__, fmt);
 ....

the obvious fix - check the length of the error response body - it's already there:

mongoose.c:889

if ( len ) conn->num_bytes_sent += mg_printf(conn, "%s", buf);

morphine

Blocking call to mg_write

Is there a recommended way to workaround the fact that mg_write is blocking ?

Sometimes, when the client drops the connection and get killed, mongoose never get notified, and mg_write blocks indefinitely. It may wait for the default timeout, which is something like 2 hours on win32.

A slight security issue?

I downloaded the new 3.5 and php bundle from google code - very convenient to have that by the way - and tested this in there, so I believe I had a clean environment to verify this on.

The issue is that while http://localhost/file.php works fine, http://localhost/file.php/ results in the source code being shown as plain text.

I played around with various characters, and found that #, instead of / also causes this behavior.

I also found that changing cgi_pattern to **.php$|**.php/$|**.php#$ fixes it.

Warning when using WinAPI function (Visual Studio 2012)

The usage of GetFullPathName(..) is wrong when the characterset of the visual studio project is set to unicode. This issues a warning (warning C4133: 'function' : incompatible types - from 'char *' to 'LPCWSTR')

The solution in use is to force using the unicode variant of the function is not really proper - but works with the majority of the WinAPI functions. In my opinion, a better solution would be to use the unicode / non-unicode variant of the function (depending on the project settings) and convert strings before using either to unicode or to non-unicode.

upload images from browser to server on windows fails

I have been trying to use the example of the upload to upload images but the bytes of a jpg files after upload is always more than the actual file bytes though through debug the cl parameter in your example holds the correct bytes length. this result the new jpg uploaded file to be corrupted.

can you give me a hint on what is the modification needed to work on windows as per issue #26? I would really appreciate it.

one small thing to mention, the normal ascii text file works fine even on windows but the binary seems to fail

Thanks in advance.

fd limit in select

when using mongoose in a program that uses a lot of file descriptors, one of mongooses sockets may be assigned a file descriptor of 1024 or higher.

on linux 3.2.0-23, fd_set holds 16 long ints, which on an LP64 system means 1024 bits. I encountered an error in FD_SET() when such a file descriptor was used. My fix was to replace select() with poll() which appears to work. It may not be portable to windows verbatim though. Here's the patch:

--- a/src/mongoose.c
+++ b/src/mongoose.c
@@ -50,6 +50,7 @@
 #include <limits.h>
 #include <stddef.h>
 #include <stdio.h>
+#include <poll.h>^M

 #if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
 #define _WIN32_WINNT 0x0400 // To make it link in VS2005
@@ -1380,15 +1381,12 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
 // reading, must give up and close the connection and exit serving thread.
 static int wait_until_socket_is_readable(struct mg_connection *conn) {
   int result;
-  struct timeval tv;
-  fd_set set;
+  struct pollfd pfd;^M

   do {
-    tv.tv_sec = 0;
-    tv.tv_usec = 300 * 1000;
-    FD_ZERO(&set);
-    FD_SET(conn->client.sock, &set);
-    result = select(conn->client.sock + 1, &set, NULL, NULL, &tv);
+    pfd.fd = conn->client.sock;^M
+    pfd.events = POLLIN;^M
+    result = poll(&pfd, 1, 300);^M
   } while ((result == 0 || (result < 0 && ERRNO == EINTR)) &&
            conn->ctx->stop_flag == 0);

Mongoose hangs if attempting to stop after OOM

When Mongoose is initializing, it can encounter an OOM error in worker_thread(). At this point the function returns. If mg_stop() is called later, an infinite loop occurs as it waits for stop_flag to be set to 2. I believe this occurs because in master_thread(), it loops while ctx->num_threads > 0, and calls pthread_cond_wait, which calls WaitForMultipleObjects() with infinite timeout.

I'm not sure if WaitForMultipleObjects() ever returns if one of the worker threads has already terminated prematurely due to OOM error (I didn't dig that deeply into the code). Either way, ctx->num_threads is never 0 because when the worker thread terminated prematurely it doesn't decrease the thread count. Hence, the infinite loop in mg_stop() while it waits for stop_flag == 2, which never occurs because of either infinite loop, infinite block, or both in master_thread() before it sets stop_flag = 2.

I think the solution would be to include the block of code at the end of worker_thread(), which locks the mutex and decreases thread count, inside the block at the top of worker_thread() if conn == NULL, so the thread count is properly updated before the worker thread returns.

I am not immediately familiar with pthreads and Winsock so I may be incorrect about the details posted here. What I do know for sure is that an infinite loop occurs in mg_stop() because stop_flag is never set to 2, and that during this time ctx->num_threads is 1.

LUA support and enable_keep_alive

Server-side LUA support is amazing. Good work !
I just found a small bug with it. When the enable_keep_alive option is enabled, .lp pages process fine but as mongoose doesn't send a Content-Length header nor closes the connection. So the browser just hangs there, expecting mode data to come.
Setting enable_keep_alive to off (which is the default setting) does not trigger the issue.

Fix for hang when sending large request with SSL enabled

There is an error in the usage of OpenSSL when reading large requests. I noticed that when testing file upload (tested with ~130kb file) having SSL enabled on the server, eventually the select() call in wait_until_socket_is_readable() would always timeout and return 0 when there was still data to be read, causing an infinite loop and a server hang. This is because when reading data from sockets with SSL, we must also call SSL_pending() because the socket might report as not readable but SSL has buffered data that needs to be drained with SSL_read(), and SSL_pending() reports this.

According to this page
http://www.rtfm.com/openssl-examples/part2.pdf
this is due to the way SSL buffers data in relation to when it actually comes through the socket and there is a function SSL_pending() to accommodate this:

"Thus, select() is an unreliable guide to whether there is SSL data ready to read. We
need some way to determine the status of the SSL buffer. This can’t be provided by the operating
system because it has no access to the SSL buffers. It must be provided OpenSSL. OpenSSL
provides exactly such a function. The function SSL_pending()"

I have coded a fix for this in mongoose.c that works when tested in my development environment. If necessary I can create a branch to merge for the update but the fix is relatively small:

Import the SSL_pending() function:

Into non-DL, around line 302 (I have not tested non-DL but I believe this is correct):
extern int SSL_pending(SSL *);

Into DL, around line 333 (added at the end of the block because I incremented the last index):
#define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)

Into the SSL function struct, arond line 381:
{"SSL_pending", NULL},

Implement use of the function in wait_until_socket_is_readble() around line 1468:
After line 1467:
result = select(conn->client.sock + 1, &set, NULL, NULL, &tv);
add this check:
if(result == 0 && conn->ssl != NULL) { result = SSL_pending(conn->ssl); }

During my testing, this check always resolved the issue.

cppcheck

http://sourceforge.net/projects/cppcheck/?source=dlp

"Possible null pointer dereference: conn - otherwise it is redundant to check it against null."

static void *call_user(struct mg_connection *conn, enum mg_event event) {
if (conn != NULL && conn->ctx != NULL) {
conn->request_info.user_data = conn->ctx->user_data;
}
return conn == NULL || conn->ctx == NULL || conn->ctx->user_callback == NULL ?
NULL : conn->ctx->user_callback(event, conn);
}
mongoose-cppcheck

user_data no longer available

Hello:

It looks as though user_data which is passed to mg_start is no longer available to callbacks.

The code for mg_start() appears to assign user_data to ctx->user_data (mongoose.cc:39) which I don't think can be accessed from the public API.
The user_data attribute of struct mg_request_info never seems to have its value set.

Is this intended behavior?

mg_request_info::user_data not available when initializing SSL

Because user_data is a member of mg_request_info it is not availbe when initalizing SSL, were the SSL context is passed to the callback instead of a mg_connection instance.

This is not very nice, if someone like to wrap mongoose in a C++ class.

One possible solution would be to make user_data a member of mg_context and passing the current context to the callback.

What do other users think?

fix for android/bionic fread() returning (EOF)

on android, fread() in bionic libc returns EOF (-1) instead of null (0) in case of errors or EOF.
this breaks cgi scripts when using mongoose on android. cgi scripts will return lots of binary garbage.
I'm using adroid NDK R8 on Linux.

here you can have a look on the fread() code from android:

http://source-android.frandroid.com/bionic/libc/stdio/fread.c

the following patch fixes my CGI problems on android:

diff --git a/mongoose.c b/mongoose.c
index 0dddf80..3cfd2d9 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -2519,7 +2519,7 @@ static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) {
to_read = (int) len;

 // Read from file, exit the loop on error
  • if ((num_read = fread(buf, 1, (size_t)to_read, fp)) == 0)
  • if ((num_read = fread(buf, 1, (size_t)to_read, fp)) <= 0)
    break;

// Send read bytes to the client, exit the loop on error

1.7.11.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.