Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
mongoose
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
esp
mongoose
Commits
3b69f5d5
Commit
3b69f5d5
authored
Oct 14, 2016
by
Deomid Ryabkov
Committed by
Cesanta Bot
Oct 14, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MG_DISABLE_DAV -> MG_ENABLE_HTTP_WEBDAV
PUBLISHED_FROM=62267ea0a8e10d8ba7bad590d1a56b179bcffce9
parent
b298d46a
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
305 additions
and
276 deletions
+305
-276
enabling-flags.md
docs/overview/build-options/enabling-flags.md
+2
-1
mongoose.c
mongoose.c
+299
-271
mongoose.h
mongoose.h
+4
-4
No files found.
docs/overview/build-options/enabling-flags.md
View file @
3b69f5d5
...
...
@@ -5,9 +5,10 @@ title: Enabling flags
-
`MG_ENABLE_CGI`
Enable CGI support
-
`MG_ENABLE_SSL`
Enable SSL/TLS support (OpenSSL API)
-
`MG_ENABLE_IPV6`
Enable IPV6 support
-
`MG_ENABLE_THREADS`
enable
`mg_start_thread()`
API
-
`MG_ENABLE_MQTT`
enable MQTT client
-
`MG_ENABLE_MQTT_BROKER`
enable MQTT broker
-
`MG_ENABLE_DNS_SERVER`
enable DNS server
-
`MG_ENABLE_COAP`
enable CoAP protocol
-
`MG_ENABLE_HTTP_WEBDAV`
enable WebDAV extensions to HTTP
-
`MG_ENABLE_GETADDRINFO`
enable
`getaddrinfo()`
in
`mg_resolve2()`
-
`MG_ENABLE_THREADS`
enable
`mg_start_thread()`
API
mongoose.c
View file @
3b69f5d5
...
...
@@ -130,6 +130,23 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
struct
mg_http_proto_data_cgi
;
MG_INTERNAL
void
mg_http_free_proto_data_cgi
(
struct
mg_http_proto_data_cgi
*
d
);
#endif
#if !MG_DISABLE_HTTP && MG_ENABLE_HTTP_WEBDAV
MG_INTERNAL
int
mg_is_dav_request
(
const
struct
mg_str
*
s
);
MG_INTERNAL
void
mg_handle_propfind
(
struct
mg_connection
*
nc
,
const
char
*
path
,
cs_stat_t
*
stp
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
);
MG_INTERNAL
void
mg_handle_lock
(
struct
mg_connection
*
nc
,
const
char
*
path
);
MG_INTERNAL
void
mg_handle_mkcol
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
);
MG_INTERNAL
void
mg_handle_move
(
struct
mg_connection
*
c
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
,
struct
http_message
*
hm
);
MG_INTERNAL
void
mg_handle_delete
(
struct
mg_connection
*
nc
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
);
MG_INTERNAL
void
mg_handle_put
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
);
#endif
#endif
/* CS_MONGOOSE_SRC_INTERNAL_H_ */
#ifdef MG_MODULE_LINES
...
...
@@ -3999,17 +4016,6 @@ static const struct {
MIME_ENTRY
(
"bmp"
,
"image/bmp"
),
{
NULL
,
0
,
NULL
}};
#if !MG_DISABLE_DAV
static
int
mg_mkdir
(
const
char
*
path
,
uint32_t
mode
)
{
#ifndef _WIN32
return
mkdir
(
path
,
mode
);
#else
(
void
)
mode
;
return
_mkdir
(
path
);
#endif
}
#endif
static
struct
mg_str
mg_get_mime_type
(
const
char
*
path
,
const
char
*
dflt
,
const
struct
mg_serve_http_opts
*
opts
)
{
const
char
*
ext
,
*
overrides
;
...
...
@@ -6196,367 +6202,114 @@ static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,
}
#endif
/* MG_DISABLE_DIRECTORY_LISTING */
#if !MG_DISABLE_DAV
static
void
mg_print_props
(
struct
mg_connection
*
nc
,
const
char
*
name
,
cs_stat_t
*
stp
)
{
char
mtime
[
64
],
buf
[
MAX_PATH_SIZE
*
3
];
time_t
t
=
stp
->
st_mtime
;
/* store in local variable for NDK compile */
mg_gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
t
);
mg_url_encode
(
name
,
strlen
(
name
),
buf
,
sizeof
(
buf
));
mg_printf
(
nc
,
"<d:response>"
"<d:href>%s</d:href>"
"<d:propstat>"
"<d:prop>"
"<d:resourcetype>%s</d:resourcetype>"
"<d:getcontentlength>%"
INT64_FMT
"</d:getcontentlength>"
"<d:getlastmodified>%s</d:getlastmodified>"
"</d:prop>"
"<d:status>HTTP/1.1 200 OK</d:status>"
"</d:propstat>"
"</d:response>
\n
"
,
buf
,
S_ISDIR
(
stp
->
st_mode
)
?
"<d:collection/>"
:
""
,
(
int64_t
)
stp
->
st_size
,
mtime
);
}
/*
* Given a directory path, find one of the files specified in the
* comma-separated list of index files `list`.
* First found index file wins. If an index file is found, then gets
* appended to the `path`, stat-ed, and result of `stat()` passed to `stp`.
* If index file is not found, then `path` and `stp` remain unchanged.
*/
MG_INTERNAL
void
mg_find_index_file
(
const
char
*
path
,
const
char
*
list
,
char
**
index_file
,
cs_stat_t
*
stp
)
{
struct
mg_str
vec
;
size_t
path_len
=
strlen
(
path
);
int
found
=
0
;
*
index_file
=
NULL
;
static
void
mg_handle_propfind
(
struct
mg_connection
*
nc
,
const
char
*
path
,
cs_stat_t
*
stp
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
static
const
char
header
[]
=
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
"Content-Type: text/xml; charset=utf-8
\r\n\r\n
"
"<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?>"
"<d:multistatus xmlns:d='DAV:'>
\n
"
;
static
const
char
footer
[]
=
"</d:multistatus>
\n
"
;
const
struct
mg_str
*
depth
=
mg_get_http_header
(
hm
,
"Depth"
);
/* Traverse index files list. For each entry, append it to the given */
/* path and see if the file exists. If it exists, break the loop */
while
((
list
=
mg_next_comma_list_entry
(
list
,
&
vec
,
NULL
))
!=
NULL
)
{
cs_stat_t
st
;
size_t
len
=
path_len
+
1
+
vec
.
len
+
1
;
*
index_file
=
(
char
*
)
MG_REALLOC
(
*
index_file
,
len
);
if
(
*
index_file
==
NULL
)
break
;
snprintf
(
*
index_file
,
len
,
"%s%c%.*s"
,
path
,
DIRSEP
,
(
int
)
vec
.
len
,
vec
.
p
);
/* Print properties for the requested resource itself */
if
(
S_ISDIR
(
stp
->
st_mode
)
&&
strcmp
(
opts
->
enable_directory_listing
,
"yes"
)
!=
0
)
{
mg_printf
(
nc
,
"%s"
,
"HTTP/1.1 403 Directory Listing Denied
\r\n\r\n
"
);
}
else
{
char
uri
[
MAX_PATH_SIZE
];
mg_send
(
nc
,
header
,
sizeof
(
header
)
-
1
);
snprintf
(
uri
,
sizeof
(
uri
),
"%.*s"
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
);
mg_print_props
(
nc
,
uri
,
stp
);
if
(
S_ISDIR
(
stp
->
st_mode
)
&&
(
depth
==
NULL
||
mg_vcmp
(
depth
,
"0"
)
!=
0
))
{
mg_scan_directory
(
nc
,
path
,
opts
,
mg_print_props
);
/* Does it exist? Is it a file? */
if
(
mg_stat
(
*
index_file
,
&
st
)
==
0
&&
S_ISREG
(
st
.
st_mode
))
{
/* Yes it does, break the loop */
*
stp
=
st
;
found
=
1
;
break
;
}
mg_send
(
nc
,
footer
,
sizeof
(
footer
)
-
1
);
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
}
#if MG_ENABLE_FAKE_DAVLOCK
/*
* Windows explorer (probably there are another WebDav clients like it)
* requires LOCK support in webdav. W/out this, it still works, but fails
* to save file: shows error message and offers "Save As".
* "Save as" works, but this message is very annoying.
* This is fake lock, which doesn't lock something, just returns LOCK token,
* UNLOCK always answers "OK".
* With this fake LOCK Windows Explorer looks happy and saves file.
* NOTE: that is not DAV LOCK imlementation, it is just a way to shut up
* Windows native DAV client. This is why FAKE LOCK is not enabed by default
*/
static
void
mg_handle_lock
(
struct
mg_connection
*
nc
,
const
char
*
path
)
{
static
const
char
*
reply
=
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
"Content-Type: text/xml; charset=utf-8
\r\n\r\n
"
"<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?>"
"<d:multistatus xmlns:d='DAV:'>
\n
"
"<D:lockdiscovery>
\n
"
"<D:activelock>
\n
"
"<D:locktoken>
\n
"
"<D:href>
\n
"
"opaquelocktoken:%s%u"
"</D:href>"
"</D:locktoken>"
"</D:activelock>
\n
"
"</D:lockdiscovery>"
"</d:multistatus>
\n
"
;
mg_printf
(
nc
,
reply
,
path
,
(
unsigned
int
)
time
(
NULL
));
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
#endif
static
void
mg_handle_mkcol
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
)
{
int
status_code
=
500
;
if
(
hm
->
body
.
len
!=
(
size_t
)
~
0
&&
hm
->
body
.
len
>
0
)
{
status_code
=
415
;
}
else
if
(
!
mg_mkdir
(
path
,
0755
))
{
status_code
=
201
;
}
else
if
(
errno
==
EEXIST
)
{
status_code
=
405
;
}
else
if
(
errno
==
EACCES
)
{
status_code
=
403
;
}
else
if
(
errno
==
ENOENT
)
{
status_code
=
409
;
}
else
{
status_code
=
500
;
if
(
!
found
)
{
MG_FREE
(
*
index_file
);
*
index_file
=
NULL
;
}
mg_http_send_error
(
nc
,
status_code
,
NULL
);
DBG
((
"[%s] [%s]"
,
path
,
(
*
index_file
?
*
index_file
:
""
))
);
}
static
int
mg_
remove_directory
(
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
dir
)
{
char
path
[
MAX_PATH_SIZE
];
struct
dirent
*
dp
;
cs_stat_t
st
;
DIR
*
dirp
;
static
int
mg_
http_send_port_based_redirect
(
struct
mg_connection
*
c
,
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
)
{
const
char
*
rewrites
=
opts
->
url_rewrites
;
struct
mg_str
a
,
b
;
char
local_port
[
20
]
=
{
'%'
}
;
if
((
dirp
=
opendir
(
dir
))
==
NULL
)
return
0
;
mg_conn_addr_to_str
(
c
,
local_port
+
1
,
sizeof
(
local_port
)
-
1
,
MG_SOCK_STRINGIFY_PORT
);
while
((
dp
=
readdir
(
dirp
))
!=
NULL
)
{
if
(
mg_is_file_hidden
((
const
char
*
)
dp
->
d_name
,
opts
,
1
))
{
continue
;
}
snprintf
(
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
mg_stat
(
path
,
&
st
);
if
(
S_ISDIR
(
st
.
st_mode
))
{
mg_remove_directory
(
opts
,
path
);
}
else
{
remove
(
path
);
while
((
rewrites
=
mg_next_comma_list_entry
(
rewrites
,
&
a
,
&
b
))
!=
NULL
)
{
if
(
mg_vcmp
(
&
a
,
local_port
)
==
0
)
{
mg_send_response_line
(
c
,
301
,
NULL
);
mg_printf
(
c
,
"Content-Length: 0
\r\n
Location: %.*s%.*s
\r\n\r\n
"
,
(
int
)
b
.
len
,
b
.
p
,
(
int
)
(
hm
->
proto
.
p
-
hm
->
uri
.
p
-
1
),
hm
->
uri
.
p
);
return
1
;
}
}
closedir
(
dirp
);
rmdir
(
dir
);
return
1
;
return
0
;
}
static
void
mg_handle_move
(
struct
mg_connection
*
c
,
MG_INTERNAL
int
mg_uri_to_local_path
(
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
,
struct
http_message
*
hm
)
{
const
struct
mg_str
*
dest
=
mg_get_http_header
(
hm
,
"Destination"
);
if
(
dest
==
NULL
)
{
mg_http_send_error
(
c
,
411
,
NULL
);
char
**
local_path
,
struct
mg_str
*
remainder
)
{
int
ok
=
1
;
const
char
*
cp
=
hm
->
uri
.
p
,
*
cp_end
=
hm
->
uri
.
p
+
hm
->
uri
.
len
;
struct
mg_str
root
=
{
NULL
,
0
};
const
char
*
file_uri_start
=
cp
;
*
local_path
=
NULL
;
remainder
->
p
=
NULL
;
remainder
->
len
=
0
;
{
/* 1. Determine which root to use. */
const
char
*
rewrites
=
opts
->
url_rewrites
;
struct
mg_str
*
hh
=
mg_get_http_header
(
hm
,
"Host"
);
struct
mg_str
a
,
b
;
/* Check rewrites first. */
while
((
rewrites
=
mg_next_comma_list_entry
(
rewrites
,
&
a
,
&
b
))
!=
NULL
)
{
if
(
a
.
len
>
1
&&
a
.
p
[
0
]
==
'@'
)
{
/* Host rewrite. */
if
(
hh
!=
NULL
&&
hh
->
len
==
a
.
len
-
1
&&
mg_ncasecmp
(
a
.
p
+
1
,
hh
->
p
,
a
.
len
-
1
)
==
0
)
{
root
=
b
;
break
;
}
}
else
{
const
char
*
p
=
(
char
*
)
memchr
(
dest
->
p
,
'/'
,
dest
->
len
);
if
(
p
!=
NULL
&&
p
[
1
]
==
'/'
&&
(
p
=
(
char
*
)
memchr
(
p
+
2
,
'/'
,
dest
->
p
+
dest
->
len
-
p
))
!=
NULL
)
{
char
buf
[
MAX_PATH_SIZE
];
snprintf
(
buf
,
sizeof
(
buf
),
"%s%.*s"
,
opts
->
dav_document_root
,
(
int
)
(
dest
->
p
+
dest
->
len
-
p
),
p
);
if
(
rename
(
path
,
buf
)
==
0
)
{
mg_http_send_error
(
c
,
200
,
NULL
);
/* Regular rewrite, URI=directory */
int
match_len
=
mg_match_prefix_n
(
a
,
hm
->
uri
);
if
(
match_len
>
0
)
{
file_uri_start
=
hm
->
uri
.
p
+
match_len
;
if
(
*
file_uri_start
==
'/'
||
file_uri_start
==
cp_end
)
{
/* Match ended at component boundary, ok. */
}
else
if
(
*
(
file_uri_start
-
1
)
==
'/'
)
{
/* Pattern ends with '/', backtrack. */
file_uri_start
--
;
}
else
{
mg_http_send_error
(
c
,
418
,
NULL
);
/* No match: must fall on the component boundary. */
continue
;
}
}
else
{
mg_http_send_error
(
c
,
500
,
NULL
);
}
}
}
static
void
mg_handle_delete
(
struct
mg_connection
*
nc
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
)
{
cs_stat_t
st
;
if
(
mg_stat
(
path
,
&
st
)
!=
0
)
{
mg_http_send_error
(
nc
,
404
,
NULL
);
}
else
if
(
S_ISDIR
(
st
.
st_mode
))
{
mg_remove_directory
(
opts
,
path
);
mg_http_send_error
(
nc
,
204
,
NULL
);
}
else
if
(
remove
(
path
)
==
0
)
{
mg_http_send_error
(
nc
,
204
,
NULL
);
}
else
{
mg_http_send_error
(
nc
,
423
,
NULL
);
}
}
/* Return -1 on error, 1 on success. */
static
int
mg_create_itermediate_directories
(
const
char
*
path
)
{
const
char
*
s
;
/* Create intermediate directories if they do not exist */
for
(
s
=
path
+
1
;
*
s
!=
'\0'
;
s
++
)
{
if
(
*
s
==
'/'
)
{
char
buf
[
MAX_PATH_SIZE
];
cs_stat_t
st
;
snprintf
(
buf
,
sizeof
(
buf
),
"%.*s"
,
(
int
)
(
s
-
path
),
path
);
buf
[
sizeof
(
buf
)
-
1
]
=
'\0'
;
if
(
mg_stat
(
buf
,
&
st
)
!=
0
&&
mg_mkdir
(
buf
,
0755
)
!=
0
)
{
return
-
1
;
}
}
}
return
1
;
}
static
void
mg_handle_put
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
)
{
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
);
cs_stat_t
st
;
const
struct
mg_str
*
cl_hdr
=
mg_get_http_header
(
hm
,
"Content-Length"
);
int
rc
,
status_code
=
mg_stat
(
path
,
&
st
)
==
0
?
200
:
201
;
mg_http_free_proto_data_file
(
&
pd
->
file
);
if
((
rc
=
mg_create_itermediate_directories
(
path
))
==
0
)
{
mg_printf
(
nc
,
"HTTP/1.1 %d OK
\r\n
Content-Length: 0
\r\n\r\n
"
,
status_code
);
}
else
if
(
rc
==
-
1
)
{
mg_http_send_error
(
nc
,
500
,
NULL
);
}
else
if
(
cl_hdr
==
NULL
)
{
mg_http_send_error
(
nc
,
411
,
NULL
);
}
else
if
((
pd
->
file
.
fp
=
fopen
(
path
,
"w+b"
))
==
NULL
)
{
mg_http_send_error
(
nc
,
500
,
NULL
);
}
else
{
const
struct
mg_str
*
range_hdr
=
mg_get_http_header
(
hm
,
"Content-Range"
);
int64_t
r1
=
0
,
r2
=
0
;
pd
->
file
.
type
=
DATA_PUT
;
mg_set_close_on_exec
(
fileno
(
pd
->
file
.
fp
));
pd
->
file
.
cl
=
to64
(
cl_hdr
->
p
);
if
(
range_hdr
!=
NULL
&&
mg_http_parse_range_header
(
range_hdr
,
&
r1
,
&
r2
)
>
0
)
{
status_code
=
206
;
fseeko
(
pd
->
file
.
fp
,
r1
,
SEEK_SET
);
pd
->
file
.
cl
=
r2
>
r1
?
r2
-
r1
+
1
:
pd
->
file
.
cl
-
r1
;
}
mg_printf
(
nc
,
"HTTP/1.1 %d OK
\r\n
Content-Length: 0
\r\n\r\n
"
,
status_code
);
/* Remove HTTP request from the mbuf, leave only payload */
mbuf_remove
(
&
nc
->
recv_mbuf
,
hm
->
message
.
len
-
hm
->
body
.
len
);
mg_http_transfer_file_data
(
nc
);
}
}
#endif
/* MG_DISABLE_DAV */
static
int
mg_is_dav_request
(
const
struct
mg_str
*
s
)
{
static
const
char
*
methods
[]
=
{
"PUT"
,
"DELETE"
,
"MKCOL"
,
"PROPFIND"
,
"MOVE"
#if MG_ENABLE_FAKE_DAVLOCK
,
"LOCK"
,
"UNLOCK"
#endif
};
size_t
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
methods
);
i
++
)
{
if
(
mg_vcmp
(
s
,
methods
[
i
])
==
0
)
{
return
1
;
}
}
return
0
;
}
/*
* Given a directory path, find one of the files specified in the
* comma-separated list of index files `list`.
* First found index file wins. If an index file is found, then gets
* appended to the `path`, stat-ed, and result of `stat()` passed to `stp`.
* If index file is not found, then `path` and `stp` remain unchanged.
*/
MG_INTERNAL
void
mg_find_index_file
(
const
char
*
path
,
const
char
*
list
,
char
**
index_file
,
cs_stat_t
*
stp
)
{
struct
mg_str
vec
;
size_t
path_len
=
strlen
(
path
);
int
found
=
0
;
*
index_file
=
NULL
;
/* Traverse index files list. For each entry, append it to the given */
/* path and see if the file exists. If it exists, break the loop */
while
((
list
=
mg_next_comma_list_entry
(
list
,
&
vec
,
NULL
))
!=
NULL
)
{
cs_stat_t
st
;
size_t
len
=
path_len
+
1
+
vec
.
len
+
1
;
*
index_file
=
(
char
*
)
MG_REALLOC
(
*
index_file
,
len
);
if
(
*
index_file
==
NULL
)
break
;
snprintf
(
*
index_file
,
len
,
"%s%c%.*s"
,
path
,
DIRSEP
,
(
int
)
vec
.
len
,
vec
.
p
);
/* Does it exist? Is it a file? */
if
(
mg_stat
(
*
index_file
,
&
st
)
==
0
&&
S_ISREG
(
st
.
st_mode
))
{
/* Yes it does, break the loop */
*
stp
=
st
;
found
=
1
;
break
;
}
}
if
(
!
found
)
{
MG_FREE
(
*
index_file
);
*
index_file
=
NULL
;
}
DBG
((
"[%s] [%s]"
,
path
,
(
*
index_file
?
*
index_file
:
""
)));
}
static
int
mg_http_send_port_based_redirect
(
struct
mg_connection
*
c
,
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
)
{
const
char
*
rewrites
=
opts
->
url_rewrites
;
struct
mg_str
a
,
b
;
char
local_port
[
20
]
=
{
'%'
};
mg_conn_addr_to_str
(
c
,
local_port
+
1
,
sizeof
(
local_port
)
-
1
,
MG_SOCK_STRINGIFY_PORT
);
while
((
rewrites
=
mg_next_comma_list_entry
(
rewrites
,
&
a
,
&
b
))
!=
NULL
)
{
if
(
mg_vcmp
(
&
a
,
local_port
)
==
0
)
{
mg_send_response_line
(
c
,
301
,
NULL
);
mg_printf
(
c
,
"Content-Length: 0
\r\n
Location: %.*s%.*s
\r\n\r\n
"
,
(
int
)
b
.
len
,
b
.
p
,
(
int
)
(
hm
->
proto
.
p
-
hm
->
uri
.
p
-
1
),
hm
->
uri
.
p
);
return
1
;
}
}
return
0
;
}
MG_INTERNAL
int
mg_uri_to_local_path
(
struct
http_message
*
hm
,
const
struct
mg_serve_http_opts
*
opts
,
char
**
local_path
,
struct
mg_str
*
remainder
)
{
int
ok
=
1
;
const
char
*
cp
=
hm
->
uri
.
p
,
*
cp_end
=
hm
->
uri
.
p
+
hm
->
uri
.
len
;
struct
mg_str
root
=
{
NULL
,
0
};
const
char
*
file_uri_start
=
cp
;
*
local_path
=
NULL
;
remainder
->
p
=
NULL
;
remainder
->
len
=
0
;
{
/* 1. Determine which root to use. */
const
char
*
rewrites
=
opts
->
url_rewrites
;
struct
mg_str
*
hh
=
mg_get_http_header
(
hm
,
"Host"
);
struct
mg_str
a
,
b
;
/* Check rewrites first. */
while
((
rewrites
=
mg_next_comma_list_entry
(
rewrites
,
&
a
,
&
b
))
!=
NULL
)
{
if
(
a
.
len
>
1
&&
a
.
p
[
0
]
==
'@'
)
{
/* Host rewrite. */
if
(
hh
!=
NULL
&&
hh
->
len
==
a
.
len
-
1
&&
mg_ncasecmp
(
a
.
p
+
1
,
hh
->
p
,
a
.
len
-
1
)
==
0
)
{
root
=
b
;
break
;
}
}
else
{
/* Regular rewrite, URI=directory */
int
match_len
=
mg_match_prefix_n
(
a
,
hm
->
uri
);
if
(
match_len
>
0
)
{
file_uri_start
=
hm
->
uri
.
p
+
match_len
;
if
(
*
file_uri_start
==
'/'
||
file_uri_start
==
cp_end
)
{
/* Match ended at component boundary, ok. */
}
else
if
(
*
(
file_uri_start
-
1
)
==
'/'
)
{
/* Pattern ends with '/', backtrack. */
file_uri_start
--
;
}
else
{
/* No match: must fall on the component boundary. */
continue
;
}
root
=
b
;
break
;
root
=
b
;
break
;
}
}
}
/* If no rewrite rules matched, use DAV or regular document root. */
if
(
root
.
p
==
NULL
)
{
#if
!MG_DISABLE_
DAV
#if
MG_ENABLE_HTTP_WEB
DAV
if
(
opts
->
dav_document_root
!=
NULL
&&
mg_is_dav_request
(
&
hm
->
method
))
{
root
.
p
=
opts
->
dav_document_root
;
root
.
len
=
strlen
(
opts
->
dav_document_root
);
...
...
@@ -6729,7 +6482,7 @@ static void mg_http_send_digest_auth_request(struct mg_connection *c,
static
void
mg_http_send_options
(
struct
mg_connection
*
nc
)
{
mg_printf
(
nc
,
"%s"
,
"HTTP/1.1 200 OK
\r\n
Allow: GET, POST, HEAD, CONNECT, OPTIONS"
#if
!MG_DISABLE_
DAV
#if
MG_ENABLE_HTTP_WEB
DAV
", MKCOL, PUT, DELETE, PROPFIND, MOVE
\r\n
DAV: 1,2"
#endif
"
\r\n\r\n
"
);
...
...
@@ -6744,8 +6497,12 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
const
struct
mg_str
*
path_info
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
int
exists
,
is_directory
,
is_dav
=
mg_is_dav_request
(
&
hm
->
method
);
int
is_cgi
;
int
exists
,
is_directory
,
is_cgi
;
#if MG_ENABLE_HTTP_WEBDAV
int
is_dav
=
mg_is_dav_request
(
&
hm
->
method
);
#else
int
is_dav
=
0
;
#endif
char
*
index_file
=
NULL
;
cs_stat_t
st
;
...
...
@@ -6796,7 +6553,7 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
mg_is_file_hidden
(
path
,
opts
,
0
/* specials are ok */
))
&&
!
mg_is_creation_request
(
hm
))
{
mg_http_send_error
(
nc
,
404
,
NULL
);
#if
!MG_DISABLE_
DAV
#if
MG_ENABLE_HTTP_WEB
DAV
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"PROPFIND"
))
{
mg_handle_propfind
(
nc
,
path
,
&
st
,
hm
,
opts
);
#if !MG_DISABLE_DAV_AUTH
...
...
@@ -6819,7 +6576,7 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"LOCK"
))
{
mg_handle_lock
(
nc
,
path
);
#endif
#endif
#endif
/* MG_ENABLE_HTTP_WEBDAV */
}
else
if
(
!
mg_vcmp
(
&
hm
->
method
,
"OPTIONS"
))
{
mg_http_send_options
(
nc
);
}
else
if
(
is_directory
&&
index_file
==
NULL
)
{
...
...
@@ -7603,6 +7360,277 @@ MG_INTERNAL void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d) {
#endif
/* MG_ENABLE_HTTP && MG_ENABLE_CGI */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/http_webdav.c"
#endif
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#if !MG_DISABLE_HTTP && MG_ENABLE_HTTP_WEBDAV
MG_INTERNAL
int
mg_is_dav_request
(
const
struct
mg_str
*
s
)
{
static
const
char
*
methods
[]
=
{
"PUT"
,
"DELETE"
,
"MKCOL"
,
"PROPFIND"
,
"MOVE"
#if MG_ENABLE_FAKE_DAVLOCK
,
"LOCK"
,
"UNLOCK"
#endif
};
size_t
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
methods
);
i
++
)
{
if
(
mg_vcmp
(
s
,
methods
[
i
])
==
0
)
{
return
1
;
}
}
return
0
;
}
static
int
mg_mkdir
(
const
char
*
path
,
uint32_t
mode
)
{
#ifndef _WIN32
return
mkdir
(
path
,
mode
);
#else
(
void
)
mode
;
return
_mkdir
(
path
);
#endif
}
static
void
mg_print_props
(
struct
mg_connection
*
nc
,
const
char
*
name
,
cs_stat_t
*
stp
)
{
char
mtime
[
64
],
buf
[
MAX_PATH_SIZE
*
3
];
time_t
t
=
stp
->
st_mtime
;
/* store in local variable for NDK compile */
mg_gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
t
);
mg_url_encode
(
name
,
strlen
(
name
),
buf
,
sizeof
(
buf
));
mg_printf
(
nc
,
"<d:response>"
"<d:href>%s</d:href>"
"<d:propstat>"
"<d:prop>"
"<d:resourcetype>%s</d:resourcetype>"
"<d:getcontentlength>%"
INT64_FMT
"</d:getcontentlength>"
"<d:getlastmodified>%s</d:getlastmodified>"
"</d:prop>"
"<d:status>HTTP/1.1 200 OK</d:status>"
"</d:propstat>"
"</d:response>
\n
"
,
buf
,
S_ISDIR
(
stp
->
st_mode
)
?
"<d:collection/>"
:
""
,
(
int64_t
)
stp
->
st_size
,
mtime
);
}
MG_INTERNAL
void
mg_handle_propfind
(
struct
mg_connection
*
nc
,
const
char
*
path
,
cs_stat_t
*
stp
,
struct
http_message
*
hm
,
struct
mg_serve_http_opts
*
opts
)
{
static
const
char
header
[]
=
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
"Content-Type: text/xml; charset=utf-8
\r\n\r\n
"
"<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?>"
"<d:multistatus xmlns:d='DAV:'>
\n
"
;
static
const
char
footer
[]
=
"</d:multistatus>
\n
"
;
const
struct
mg_str
*
depth
=
mg_get_http_header
(
hm
,
"Depth"
);
/* Print properties for the requested resource itself */
if
(
S_ISDIR
(
stp
->
st_mode
)
&&
strcmp
(
opts
->
enable_directory_listing
,
"yes"
)
!=
0
)
{
mg_printf
(
nc
,
"%s"
,
"HTTP/1.1 403 Directory Listing Denied
\r\n\r\n
"
);
}
else
{
char
uri
[
MAX_PATH_SIZE
];
mg_send
(
nc
,
header
,
sizeof
(
header
)
-
1
);
snprintf
(
uri
,
sizeof
(
uri
),
"%.*s"
,
(
int
)
hm
->
uri
.
len
,
hm
->
uri
.
p
);
mg_print_props
(
nc
,
uri
,
stp
);
if
(
S_ISDIR
(
stp
->
st_mode
)
&&
(
depth
==
NULL
||
mg_vcmp
(
depth
,
"0"
)
!=
0
))
{
mg_scan_directory
(
nc
,
path
,
opts
,
mg_print_props
);
}
mg_send
(
nc
,
footer
,
sizeof
(
footer
)
-
1
);
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
}
#if MG_ENABLE_FAKE_DAVLOCK
/*
* Windows explorer (probably there are another WebDav clients like it)
* requires LOCK support in webdav. W/out this, it still works, but fails
* to save file: shows error message and offers "Save As".
* "Save as" works, but this message is very annoying.
* This is fake lock, which doesn't lock something, just returns LOCK token,
* UNLOCK always answers "OK".
* With this fake LOCK Windows Explorer looks happy and saves file.
* NOTE: that is not DAV LOCK imlementation, it is just a way to shut up
* Windows native DAV client. This is why FAKE LOCK is not enabed by default
*/
MG_INTERNAL
void
mg_handle_lock
(
struct
mg_connection
*
nc
,
const
char
*
path
)
{
static
const
char
*
reply
=
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
"Content-Type: text/xml; charset=utf-8
\r\n\r\n
"
"<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?>"
"<d:multistatus xmlns:d='DAV:'>
\n
"
"<D:lockdiscovery>
\n
"
"<D:activelock>
\n
"
"<D:locktoken>
\n
"
"<D:href>
\n
"
"opaquelocktoken:%s%u"
"</D:href>"
"</D:locktoken>"
"</D:activelock>
\n
"
"</D:lockdiscovery>"
"</d:multistatus>
\n
"
;
mg_printf
(
nc
,
reply
,
path
,
(
unsigned
int
)
time
(
NULL
));
nc
->
flags
|=
MG_F_SEND_AND_CLOSE
;
}
#endif
MG_INTERNAL
void
mg_handle_mkcol
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
)
{
int
status_code
=
500
;
if
(
hm
->
body
.
len
!=
(
size_t
)
~
0
&&
hm
->
body
.
len
>
0
)
{
status_code
=
415
;
}
else
if
(
!
mg_mkdir
(
path
,
0755
))
{
status_code
=
201
;
}
else
if
(
errno
==
EEXIST
)
{
status_code
=
405
;
}
else
if
(
errno
==
EACCES
)
{
status_code
=
403
;
}
else
if
(
errno
==
ENOENT
)
{
status_code
=
409
;
}
else
{
status_code
=
500
;
}
mg_http_send_error
(
nc
,
status_code
,
NULL
);
}
static
int
mg_remove_directory
(
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
dir
)
{
char
path
[
MAX_PATH_SIZE
];
struct
dirent
*
dp
;
cs_stat_t
st
;
DIR
*
dirp
;
if
((
dirp
=
opendir
(
dir
))
==
NULL
)
return
0
;
while
((
dp
=
readdir
(
dirp
))
!=
NULL
)
{
if
(
mg_is_file_hidden
((
const
char
*
)
dp
->
d_name
,
opts
,
1
))
{
continue
;
}
snprintf
(
path
,
sizeof
(
path
),
"%s%c%s"
,
dir
,
'/'
,
dp
->
d_name
);
mg_stat
(
path
,
&
st
);
if
(
S_ISDIR
(
st
.
st_mode
))
{
mg_remove_directory
(
opts
,
path
);
}
else
{
remove
(
path
);
}
}
closedir
(
dirp
);
rmdir
(
dir
);
return
1
;
}
MG_INTERNAL
void
mg_handle_move
(
struct
mg_connection
*
c
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
,
struct
http_message
*
hm
)
{
const
struct
mg_str
*
dest
=
mg_get_http_header
(
hm
,
"Destination"
);
if
(
dest
==
NULL
)
{
mg_http_send_error
(
c
,
411
,
NULL
);
}
else
{
const
char
*
p
=
(
char
*
)
memchr
(
dest
->
p
,
'/'
,
dest
->
len
);
if
(
p
!=
NULL
&&
p
[
1
]
==
'/'
&&
(
p
=
(
char
*
)
memchr
(
p
+
2
,
'/'
,
dest
->
p
+
dest
->
len
-
p
))
!=
NULL
)
{
char
buf
[
MAX_PATH_SIZE
];
snprintf
(
buf
,
sizeof
(
buf
),
"%s%.*s"
,
opts
->
dav_document_root
,
(
int
)
(
dest
->
p
+
dest
->
len
-
p
),
p
);
if
(
rename
(
path
,
buf
)
==
0
)
{
mg_http_send_error
(
c
,
200
,
NULL
);
}
else
{
mg_http_send_error
(
c
,
418
,
NULL
);
}
}
else
{
mg_http_send_error
(
c
,
500
,
NULL
);
}
}
}
MG_INTERNAL
void
mg_handle_delete
(
struct
mg_connection
*
nc
,
const
struct
mg_serve_http_opts
*
opts
,
const
char
*
path
)
{
cs_stat_t
st
;
if
(
mg_stat
(
path
,
&
st
)
!=
0
)
{
mg_http_send_error
(
nc
,
404
,
NULL
);
}
else
if
(
S_ISDIR
(
st
.
st_mode
))
{
mg_remove_directory
(
opts
,
path
);
mg_http_send_error
(
nc
,
204
,
NULL
);
}
else
if
(
remove
(
path
)
==
0
)
{
mg_http_send_error
(
nc
,
204
,
NULL
);
}
else
{
mg_http_send_error
(
nc
,
423
,
NULL
);
}
}
/* Return -1 on error, 1 on success. */
static
int
mg_create_itermediate_directories
(
const
char
*
path
)
{
const
char
*
s
;
/* Create intermediate directories if they do not exist */
for
(
s
=
path
+
1
;
*
s
!=
'\0'
;
s
++
)
{
if
(
*
s
==
'/'
)
{
char
buf
[
MAX_PATH_SIZE
];
cs_stat_t
st
;
snprintf
(
buf
,
sizeof
(
buf
),
"%.*s"
,
(
int
)
(
s
-
path
),
path
);
buf
[
sizeof
(
buf
)
-
1
]
=
'\0'
;
if
(
mg_stat
(
buf
,
&
st
)
!=
0
&&
mg_mkdir
(
buf
,
0755
)
!=
0
)
{
return
-
1
;
}
}
}
return
1
;
}
MG_INTERNAL
void
mg_handle_put
(
struct
mg_connection
*
nc
,
const
char
*
path
,
struct
http_message
*
hm
)
{
struct
mg_http_proto_data
*
pd
=
mg_http_get_proto_data
(
nc
);
cs_stat_t
st
;
const
struct
mg_str
*
cl_hdr
=
mg_get_http_header
(
hm
,
"Content-Length"
);
int
rc
,
status_code
=
mg_stat
(
path
,
&
st
)
==
0
?
200
:
201
;
mg_http_free_proto_data_file
(
&
pd
->
file
);
if
((
rc
=
mg_create_itermediate_directories
(
path
))
==
0
)
{
mg_printf
(
nc
,
"HTTP/1.1 %d OK
\r\n
Content-Length: 0
\r\n\r\n
"
,
status_code
);
}
else
if
(
rc
==
-
1
)
{
mg_http_send_error
(
nc
,
500
,
NULL
);
}
else
if
(
cl_hdr
==
NULL
)
{
mg_http_send_error
(
nc
,
411
,
NULL
);
}
else
if
((
pd
->
file
.
fp
=
fopen
(
path
,
"w+b"
))
==
NULL
)
{
mg_http_send_error
(
nc
,
500
,
NULL
);
}
else
{
const
struct
mg_str
*
range_hdr
=
mg_get_http_header
(
hm
,
"Content-Range"
);
int64_t
r1
=
0
,
r2
=
0
;
pd
->
file
.
type
=
DATA_PUT
;
mg_set_close_on_exec
(
fileno
(
pd
->
file
.
fp
));
pd
->
file
.
cl
=
to64
(
cl_hdr
->
p
);
if
(
range_hdr
!=
NULL
&&
mg_http_parse_range_header
(
range_hdr
,
&
r1
,
&
r2
)
>
0
)
{
status_code
=
206
;
fseeko
(
pd
->
file
.
fp
,
r1
,
SEEK_SET
);
pd
->
file
.
cl
=
r2
>
r1
?
r2
-
r1
+
1
:
pd
->
file
.
cl
-
r1
;
}
mg_printf
(
nc
,
"HTTP/1.1 %d OK
\r\n
Content-Length: 0
\r\n\r\n
"
,
status_code
);
/* Remove HTTP request from the mbuf, leave only payload */
mbuf_remove
(
&
nc
->
recv_mbuf
,
hm
->
message
.
len
-
hm
->
body
.
len
);
mg_http_transfer_file_data
(
nc
);
}
}
#endif
/* !MG_DISABLE_HTTP && MG_ENABLE_HTTP_WEBDAV */
#ifdef MG_MODULE_LINES
#line 1 "mongoose/src/util.c"
#endif
/*
...
...
@@ -9772,7 +9800,7 @@ int mg_set_protocol_coap(struct mg_connection *nc) {
return
0
;
}
#endif
/* MG_
DIS
ABLE_COAP */
#endif
/* MG_
EN
ABLE_COAP */
#ifdef MG_MODULE_LINES
#line 1 "common/platforms/cc3200/cc3200_libc.c"
#endif
...
...
mongoose.h
View file @
3b69f5d5
...
...
@@ -1215,10 +1215,6 @@ const char *c_strnstr(const char *s, const char *find, size_t slen);
#define MG_DISABLE_HTTP_WEBSOCKET 0
#endif
#ifndef MG_DISABLE_DAV
#define MG_DISABLE_DAV 0
#endif
#ifndef MG_DISABLE_PFS
#define MG_DISABLE_PFS 0
#endif
...
...
@@ -1275,6 +1271,10 @@ const char *c_strnstr(const char *s, const char *find, size_t slen);
#define MG_ENABLE_HTTP_STREAMING_MULTIPART 0
#endif
#ifndef MG_ENABLE_HTTP_WEBDAV
#define MG_ENABLE_HTTP_WEBDAV 0
#endif
#ifndef MG_ENABLE_IPV6
#define MG_ENABLE_IPV6 0
#endif
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment