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
988b40f7
Commit
988b40f7
authored
Nov 24, 2013
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moved webdav functions into webdav.c
parent
b5fdd48d
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
439 additions
and
129 deletions
+439
-129
Makefile
build/Makefile
+1
-1
mongoose.c
build/src/mongoose.c
+0
-64
util.c
build/src/util.c
+4
-0
webdav.c
build/src/webdav.c
+61
-0
websocket.c
build/src/websocket.c
+309
-0
mongoose.c
mongoose.c
+64
-64
No files found.
build/Makefile
View file @
988b40f7
...
...
@@ -30,7 +30,7 @@ SOURCES = src/internal.h src/util.c src/string.c src/parse_date.c \
src/options.c src/crypto.c src/auth.c src/win32.c src/unix.c
\
src/mg_printf.c src/ssl.c src/http_client.c src/mime.c
\
src/directory.c src/log.c src/parse_http.c src/io.c src/cgi.c
\
src/upload.c src/websocket.c src/mongoose.c src/lua.c
src/upload.c src/websocket.c src/
webdav.c src/
mongoose.c src/lua.c
TINY_SOURCES
=
../mongoose.c main.c
LUA_SOURCES
=
$(TINY_SOURCES)
lua_5.2.1.c
...
...
build/src/mongoose.c
View file @
988b40f7
...
...
@@ -190,10 +190,6 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
return
0
;
}
static
void
gmt_time_string
(
char
*
buf
,
size_t
buf_len
,
time_t
*
t
)
{
strftime
(
buf
,
buf_len
,
"%a, %d %b %Y %H:%M:%S GMT"
,
gmtime
(
t
));
}
static
void
construct_etag
(
char
*
buf
,
size_t
buf_len
,
const
struct
file
*
filep
)
{
snprintf
(
buf
,
buf_len
,
"
\"
%lx.%"
INT64_FMT
"
\"
"
,
...
...
@@ -587,66 +583,6 @@ static void handle_options_request(struct mg_connection *conn) {
mg_write
(
conn
,
reply
,
sizeof
(
reply
)
-
1
);
}
// Writes PROPFIND properties for a collection element
static
void
print_props
(
struct
mg_connection
*
conn
,
const
char
*
uri
,
struct
file
*
filep
)
{
char
mtime
[
64
];
gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
filep
->
modification_time
);
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"<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
"
,
uri
,
filep
->
is_directory
?
"<d:collection/>"
:
""
,
filep
->
size
,
mtime
);
}
static
void
print_dav_dir_entry
(
struct
de
*
de
,
void
*
data
)
{
char
href
[
PATH_MAX
];
char
href_encoded
[
PATH_MAX
];
struct
mg_connection
*
conn
=
(
struct
mg_connection
*
)
data
;
mg_snprintf
(
href
,
sizeof
(
href
),
"%s%s"
,
conn
->
request_info
.
uri
,
de
->
file_name
);
mg_url_encode
(
href
,
href_encoded
,
PATH_MAX
-
1
);
print_props
(
conn
,
href_encoded
,
&
de
->
file
);
}
static
void
handle_propfind
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
const
char
*
depth
=
mg_get_header
(
conn
,
"Depth"
);
conn
->
must_close
=
1
;
conn
->
status_code
=
207
;
mg_printf
(
conn
,
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
"Content-Type: text/xml; charset=utf-8
\r\n\r\n
"
);
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?>"
"<d:multistatus xmlns:d='DAV:'>
\n
"
);
// Print properties for the requested resource itself
print_props
(
conn
,
conn
->
request_info
.
uri
,
filep
);
// If it is a directory, print directory entries too if Depth is not 0
if
(
filep
->
is_directory
&&
!
mg_strcasecmp
(
conn
->
ctx
->
config
[
ENABLE_DIRECTORY_LISTING
],
"yes"
)
&&
(
depth
==
NULL
||
strcmp
(
depth
,
"0"
)
!=
0
))
{
scan_directory
(
conn
,
path
,
conn
,
&
print_dav_dir_entry
);
}
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"%s
\n
"
,
"</d:multistatus>"
);
}
static
int
isbyte
(
int
n
)
{
return
n
>=
0
&&
n
<=
255
;
}
...
...
build/src/util.c
View file @
988b40f7
...
...
@@ -24,3 +24,7 @@ static void sockaddr_to_string(char *buf, size_t len,
inet_ntop
(
usa
->
sa
.
sa_family
,
(
void
*
)
&
usa
->
sin
.
sin_addr
,
buf
,
len
);
#endif
}
static
void
gmt_time_string
(
char
*
buf
,
size_t
buf_len
,
time_t
*
t
)
{
strftime
(
buf
,
buf_len
,
"%a, %d %b %Y %H:%M:%S GMT"
,
gmtime
(
t
));
}
build/src/webdav.c
0 → 100644
View file @
988b40f7
#include "internal.h"
// Writes PROPFIND properties for a collection element
static
void
print_props
(
struct
mg_connection
*
conn
,
const
char
*
uri
,
struct
file
*
filep
)
{
char
mtime
[
64
];
gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
filep
->
modification_time
);
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"<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
"
,
uri
,
filep
->
is_directory
?
"<d:collection/>"
:
""
,
filep
->
size
,
mtime
);
}
static
void
print_dav_dir_entry
(
struct
de
*
de
,
void
*
data
)
{
char
href
[
PATH_MAX
];
char
href_encoded
[
PATH_MAX
];
struct
mg_connection
*
conn
=
(
struct
mg_connection
*
)
data
;
mg_snprintf
(
href
,
sizeof
(
href
),
"%s%s"
,
conn
->
request_info
.
uri
,
de
->
file_name
);
mg_url_encode
(
href
,
href_encoded
,
PATH_MAX
-
1
);
print_props
(
conn
,
href_encoded
,
&
de
->
file
);
}
static
void
handle_propfind
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
const
char
*
depth
=
mg_get_header
(
conn
,
"Depth"
);
conn
->
must_close
=
1
;
conn
->
status_code
=
207
;
mg_printf
(
conn
,
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
"Content-Type: text/xml; charset=utf-8
\r\n\r\n
"
);
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?>"
"<d:multistatus xmlns:d='DAV:'>
\n
"
);
// Print properties for the requested resource itself
print_props
(
conn
,
conn
->
request_info
.
uri
,
filep
);
// If it is a directory, print directory entries too if Depth is not 0
if
(
filep
->
is_directory
&&
!
mg_strcasecmp
(
conn
->
ctx
->
config
[
ENABLE_DIRECTORY_LISTING
],
"yes"
)
&&
(
depth
==
NULL
||
strcmp
(
depth
,
"0"
)
!=
0
))
{
scan_directory
(
conn
,
path
,
conn
,
&
print_dav_dir_entry
);
}
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"%s
\n
"
,
"</d:multistatus>"
);
}
build/src/websocket.c
0 → 100644
View file @
988b40f7
#include "internal.h"
#if defined(USE_WEBSOCKET)
// START OF SHA-1 code
// Copyright(c) By Steve Reid <steve@edmweb.com>
#define SHA1HANDSOFF
#if defined(__sun)
#include "solarisfixes.h"
#endif
union
char64long16
{
unsigned
char
c
[
64
];
uint32_t
l
[
16
];
};
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
static
uint32_t
blk0
(
union
char64long16
*
block
,
int
i
)
{
// Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN
if
(
!
is_big_endian
())
{
block
->
l
[
i
]
=
(
rol
(
block
->
l
[
i
],
24
)
&
0xFF00FF00
)
|
(
rol
(
block
->
l
[
i
],
8
)
&
0x00FF00FF
);
}
return
block
->
l
[
i
];
}
#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))
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
typedef
struct
{
uint32_t
state
[
5
];
uint32_t
count
[
2
];
unsigned
char
buffer
[
64
];
}
SHA1_CTX
;
static
void
SHA1Transform
(
uint32_t
state
[
5
],
const
unsigned
char
buffer
[
64
])
{
uint32_t
a
,
b
,
c
,
d
,
e
;
union
char64long16
block
[
1
];
memcpy
(
block
,
buffer
,
64
);
a
=
state
[
0
];
b
=
state
[
1
];
c
=
state
[
2
];
d
=
state
[
3
];
e
=
state
[
4
];
R0
(
a
,
b
,
c
,
d
,
e
,
0
);
R0
(
e
,
a
,
b
,
c
,
d
,
1
);
R0
(
d
,
e
,
a
,
b
,
c
,
2
);
R0
(
c
,
d
,
e
,
a
,
b
,
3
);
R0
(
b
,
c
,
d
,
e
,
a
,
4
);
R0
(
a
,
b
,
c
,
d
,
e
,
5
);
R0
(
e
,
a
,
b
,
c
,
d
,
6
);
R0
(
d
,
e
,
a
,
b
,
c
,
7
);
R0
(
c
,
d
,
e
,
a
,
b
,
8
);
R0
(
b
,
c
,
d
,
e
,
a
,
9
);
R0
(
a
,
b
,
c
,
d
,
e
,
10
);
R0
(
e
,
a
,
b
,
c
,
d
,
11
);
R0
(
d
,
e
,
a
,
b
,
c
,
12
);
R0
(
c
,
d
,
e
,
a
,
b
,
13
);
R0
(
b
,
c
,
d
,
e
,
a
,
14
);
R0
(
a
,
b
,
c
,
d
,
e
,
15
);
R1
(
e
,
a
,
b
,
c
,
d
,
16
);
R1
(
d
,
e
,
a
,
b
,
c
,
17
);
R1
(
c
,
d
,
e
,
a
,
b
,
18
);
R1
(
b
,
c
,
d
,
e
,
a
,
19
);
R2
(
a
,
b
,
c
,
d
,
e
,
20
);
R2
(
e
,
a
,
b
,
c
,
d
,
21
);
R2
(
d
,
e
,
a
,
b
,
c
,
22
);
R2
(
c
,
d
,
e
,
a
,
b
,
23
);
R2
(
b
,
c
,
d
,
e
,
a
,
24
);
R2
(
a
,
b
,
c
,
d
,
e
,
25
);
R2
(
e
,
a
,
b
,
c
,
d
,
26
);
R2
(
d
,
e
,
a
,
b
,
c
,
27
);
R2
(
c
,
d
,
e
,
a
,
b
,
28
);
R2
(
b
,
c
,
d
,
e
,
a
,
29
);
R2
(
a
,
b
,
c
,
d
,
e
,
30
);
R2
(
e
,
a
,
b
,
c
,
d
,
31
);
R2
(
d
,
e
,
a
,
b
,
c
,
32
);
R2
(
c
,
d
,
e
,
a
,
b
,
33
);
R2
(
b
,
c
,
d
,
e
,
a
,
34
);
R2
(
a
,
b
,
c
,
d
,
e
,
35
);
R2
(
e
,
a
,
b
,
c
,
d
,
36
);
R2
(
d
,
e
,
a
,
b
,
c
,
37
);
R2
(
c
,
d
,
e
,
a
,
b
,
38
);
R2
(
b
,
c
,
d
,
e
,
a
,
39
);
R3
(
a
,
b
,
c
,
d
,
e
,
40
);
R3
(
e
,
a
,
b
,
c
,
d
,
41
);
R3
(
d
,
e
,
a
,
b
,
c
,
42
);
R3
(
c
,
d
,
e
,
a
,
b
,
43
);
R3
(
b
,
c
,
d
,
e
,
a
,
44
);
R3
(
a
,
b
,
c
,
d
,
e
,
45
);
R3
(
e
,
a
,
b
,
c
,
d
,
46
);
R3
(
d
,
e
,
a
,
b
,
c
,
47
);
R3
(
c
,
d
,
e
,
a
,
b
,
48
);
R3
(
b
,
c
,
d
,
e
,
a
,
49
);
R3
(
a
,
b
,
c
,
d
,
e
,
50
);
R3
(
e
,
a
,
b
,
c
,
d
,
51
);
R3
(
d
,
e
,
a
,
b
,
c
,
52
);
R3
(
c
,
d
,
e
,
a
,
b
,
53
);
R3
(
b
,
c
,
d
,
e
,
a
,
54
);
R3
(
a
,
b
,
c
,
d
,
e
,
55
);
R3
(
e
,
a
,
b
,
c
,
d
,
56
);
R3
(
d
,
e
,
a
,
b
,
c
,
57
);
R3
(
c
,
d
,
e
,
a
,
b
,
58
);
R3
(
b
,
c
,
d
,
e
,
a
,
59
);
R4
(
a
,
b
,
c
,
d
,
e
,
60
);
R4
(
e
,
a
,
b
,
c
,
d
,
61
);
R4
(
d
,
e
,
a
,
b
,
c
,
62
);
R4
(
c
,
d
,
e
,
a
,
b
,
63
);
R4
(
b
,
c
,
d
,
e
,
a
,
64
);
R4
(
a
,
b
,
c
,
d
,
e
,
65
);
R4
(
e
,
a
,
b
,
c
,
d
,
66
);
R4
(
d
,
e
,
a
,
b
,
c
,
67
);
R4
(
c
,
d
,
e
,
a
,
b
,
68
);
R4
(
b
,
c
,
d
,
e
,
a
,
69
);
R4
(
a
,
b
,
c
,
d
,
e
,
70
);
R4
(
e
,
a
,
b
,
c
,
d
,
71
);
R4
(
d
,
e
,
a
,
b
,
c
,
72
);
R4
(
c
,
d
,
e
,
a
,
b
,
73
);
R4
(
b
,
c
,
d
,
e
,
a
,
74
);
R4
(
a
,
b
,
c
,
d
,
e
,
75
);
R4
(
e
,
a
,
b
,
c
,
d
,
76
);
R4
(
d
,
e
,
a
,
b
,
c
,
77
);
R4
(
c
,
d
,
e
,
a
,
b
,
78
);
R4
(
b
,
c
,
d
,
e
,
a
,
79
);
state
[
0
]
+=
a
;
state
[
1
]
+=
b
;
state
[
2
]
+=
c
;
state
[
3
]
+=
d
;
state
[
4
]
+=
e
;
a
=
b
=
c
=
d
=
e
=
0
;
memset
(
block
,
'\0'
,
sizeof
(
block
));
}
static
void
SHA1Init
(
SHA1_CTX
*
context
)
{
context
->
state
[
0
]
=
0x67452301
;
context
->
state
[
1
]
=
0xEFCDAB89
;
context
->
state
[
2
]
=
0x98BADCFE
;
context
->
state
[
3
]
=
0x10325476
;
context
->
state
[
4
]
=
0xC3D2E1F0
;
context
->
count
[
0
]
=
context
->
count
[
1
]
=
0
;
}
static
void
SHA1Update
(
SHA1_CTX
*
context
,
const
unsigned
char
*
data
,
uint32_t
len
)
{
uint32_t
i
,
j
;
j
=
context
->
count
[
0
];
if
((
context
->
count
[
0
]
+=
len
<<
3
)
<
j
)
context
->
count
[
1
]
++
;
context
->
count
[
1
]
+=
(
len
>>
29
);
j
=
(
j
>>
3
)
&
63
;
if
((
j
+
len
)
>
63
)
{
memcpy
(
&
context
->
buffer
[
j
],
data
,
(
i
=
64
-
j
));
SHA1Transform
(
context
->
state
,
context
->
buffer
);
for
(
;
i
+
63
<
len
;
i
+=
64
)
{
SHA1Transform
(
context
->
state
,
&
data
[
i
]);
}
j
=
0
;
}
else
i
=
0
;
memcpy
(
&
context
->
buffer
[
j
],
&
data
[
i
],
len
-
i
);
}
static
void
SHA1Final
(
unsigned
char
digest
[
20
],
SHA1_CTX
*
context
)
{
unsigned
i
;
unsigned
char
finalcount
[
8
],
c
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
finalcount
[
i
]
=
(
unsigned
char
)((
context
->
count
[(
i
>=
4
?
0
:
1
)]
>>
((
3
-
(
i
&
3
))
*
8
)
)
&
255
);
}
c
=
0200
;
SHA1Update
(
context
,
&
c
,
1
);
while
((
context
->
count
[
0
]
&
504
)
!=
448
)
{
c
=
0000
;
SHA1Update
(
context
,
&
c
,
1
);
}
SHA1Update
(
context
,
finalcount
,
8
);
for
(
i
=
0
;
i
<
20
;
i
++
)
{
digest
[
i
]
=
(
unsigned
char
)
((
context
->
state
[
i
>>
2
]
>>
((
3
-
(
i
&
3
))
*
8
)
)
&
255
);
}
memset
(
context
,
'\0'
,
sizeof
(
*
context
));
memset
(
&
finalcount
,
'\0'
,
sizeof
(
finalcount
));
}
// END OF SHA1 CODE
static
void
base64_encode
(
const
unsigned
char
*
src
,
int
src_len
,
char
*
dst
)
{
static
const
char
*
b64
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
;
int
i
,
j
,
a
,
b
,
c
;
for
(
i
=
j
=
0
;
i
<
src_len
;
i
+=
3
)
{
a
=
src
[
i
];
b
=
i
+
1
>=
src_len
?
0
:
src
[
i
+
1
];
c
=
i
+
2
>=
src_len
?
0
:
src
[
i
+
2
];
dst
[
j
++
]
=
b64
[
a
>>
2
];
dst
[
j
++
]
=
b64
[((
a
&
3
)
<<
4
)
|
(
b
>>
4
)];
if
(
i
+
1
<
src_len
)
{
dst
[
j
++
]
=
b64
[(
b
&
15
)
<<
2
|
(
c
>>
6
)];
}
if
(
i
+
2
<
src_len
)
{
dst
[
j
++
]
=
b64
[
c
&
63
];
}
}
while
(
j
%
4
!=
0
)
{
dst
[
j
++
]
=
'='
;
}
dst
[
j
++
]
=
'\0'
;
}
void
mg_websocket_handshake
(
struct
mg_connection
*
conn
)
{
static
const
char
*
magic
=
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
;
char
buf
[
100
],
sha
[
20
],
b64_sha
[
sizeof
(
sha
)
*
2
];
SHA1_CTX
sha_ctx
;
mg_snprintf
(
buf
,
sizeof
(
buf
),
"%s%s"
,
mg_get_header
(
conn
,
"Sec-WebSocket-Key"
),
magic
);
SHA1Init
(
&
sha_ctx
);
SHA1Update
(
&
sha_ctx
,
(
unsigned
char
*
)
buf
,
strlen
(
buf
));
SHA1Final
((
unsigned
char
*
)
sha
,
&
sha_ctx
);
base64_encode
((
unsigned
char
*
)
sha
,
sizeof
(
sha
),
b64_sha
);
mg_printf
(
conn
,
"%s%s%s"
,
"HTTP/1.1 101 Switching Protocols
\r\n
"
"Upgrade: websocket
\r\n
"
"Connection: Upgrade
\r\n
"
"Sec-WebSocket-Accept: "
,
b64_sha
,
"
\r\n\r\n
"
);
}
int
mg_websocket_read
(
struct
mg_connection
*
conn
,
int
*
bits
,
char
**
data
)
{
// Pointer to the beginning of the portion of the incoming websocket message
// queue. The original websocket upgrade request is never removed,
// so the queue begins after it.
unsigned
char
*
buf
=
(
unsigned
char
*
)
conn
->
buf
+
conn
->
request_len
;
int
n
,
stop
=
0
;
size_t
i
,
len
,
mask_len
,
data_len
,
header_len
,
body_len
;
char
mask
[
4
];
assert
(
conn
->
content_len
==
0
);
// Loop continuously, reading messages from the socket, invoking the callback,
// and waiting repeatedly until an error occurs.
while
(
!
stop
)
{
header_len
=
0
;
// body_len is the length of the entire queue in bytes
// len is the length of the current message
// data_len is the length of the current message's data payload
// header_len is the length of the current message's header
if
((
body_len
=
conn
->
data_len
-
conn
->
request_len
)
>=
2
)
{
len
=
buf
[
1
]
&
127
;
mask_len
=
buf
[
1
]
&
128
?
4
:
0
;
if
(
len
<
126
&&
body_len
>=
mask_len
)
{
data_len
=
len
;
header_len
=
2
+
mask_len
;
}
else
if
(
len
==
126
&&
body_len
>=
4
+
mask_len
)
{
header_len
=
4
+
mask_len
;
data_len
=
((((
int
)
buf
[
2
])
<<
8
)
+
buf
[
3
]);
}
else
if
(
body_len
>=
10
+
mask_len
)
{
header_len
=
10
+
mask_len
;
data_len
=
(((
uint64_t
)
htonl
(
*
(
uint32_t
*
)
&
buf
[
2
]))
<<
32
)
+
htonl
(
*
(
uint32_t
*
)
&
buf
[
6
]);
}
}
// Data layout is as follows:
// conn->buf buf
// v v frame1 | frame2
// |---------------------|----------------|--------------|-------
// | |<--header_len-->|<--data_len-->|
// |<-conn->request_len->|<-----body_len----------->|
// |<-------------------conn->data_len------------->|
if
(
header_len
>
0
)
{
// Allocate space to hold websocket payload
if
((
*
data
=
malloc
(
data_len
))
==
NULL
)
{
// Allocation failed, exit the loop and then close the connection
// TODO: notify user about the failure
data_len
=
0
;
break
;
}
// Save mask and bits, otherwise it may be clobbered by memmove below
*
bits
=
buf
[
0
];
memcpy
(
mask
,
buf
+
header_len
-
mask_len
,
mask_len
);
// Read frame payload into the allocated buffer.
assert
(
body_len
>=
header_len
);
if
(
data_len
+
header_len
>
body_len
)
{
len
=
body_len
-
header_len
;
memcpy
(
*
data
,
buf
+
header_len
,
len
);
// TODO: handle pull error
pull_all
(
NULL
,
conn
,
*
data
+
len
,
data_len
-
len
);
conn
->
data_len
=
conn
->
request_len
;
}
else
{
len
=
data_len
+
header_len
;
memcpy
(
*
data
,
buf
+
header_len
,
data_len
);
memmove
(
buf
,
buf
+
len
,
body_len
-
len
);
conn
->
data_len
-=
len
;
}
// Apply mask if necessary
if
(
mask_len
>
0
)
{
for
(
i
=
0
;
i
<
data_len
;
i
++
)
{
(
*
data
)[
i
]
^=
mask
[
i
%
4
];
}
}
return
data_len
;
}
else
{
// Buffering websocket request
if
((
n
=
pull
(
NULL
,
conn
,
conn
->
buf
+
conn
->
data_len
,
conn
->
buf_size
-
conn
->
data_len
))
<=
0
)
{
break
;
}
conn
->
data_len
+=
n
;
}
}
return
0
;
}
int
mg_websocket_write
(
struct
mg_connection
*
conn
,
int
opcode
,
const
char
*
data
,
size_t
data_len
)
{
unsigned
char
*
copy
;
size_t
copy_len
=
0
;
int
retval
=
-
1
;
if
((
copy
=
(
unsigned
char
*
)
malloc
(
data_len
+
10
))
==
NULL
)
{
return
-
1
;
}
copy
[
0
]
=
0x80
+
(
opcode
&
0x0f
);
// Frame format: http://tools.ietf.org/html/rfc6455#section-5.2
if
(
data_len
<
126
)
{
// Inline 7-bit length field
copy
[
1
]
=
data_len
;
memcpy
(
copy
+
2
,
data
,
data_len
);
copy_len
=
2
+
data_len
;
}
else
if
(
data_len
<=
0xFFFF
)
{
// 16-bit length field
copy
[
1
]
=
126
;
*
(
uint16_t
*
)
(
copy
+
2
)
=
htons
(
data_len
);
memcpy
(
copy
+
4
,
data
,
data_len
);
copy_len
=
4
+
data_len
;
}
else
{
// 64-bit length field
copy
[
1
]
=
127
;
*
(
uint32_t
*
)
(
copy
+
2
)
=
htonl
((
uint64_t
)
data_len
>>
32
);
*
(
uint32_t
*
)
(
copy
+
6
)
=
htonl
(
data_len
&
0xffffffff
);
memcpy
(
copy
+
10
,
data
,
data_len
);
copy_len
=
10
+
data_len
;
}
// Not thread safe
if
(
copy_len
>
0
)
{
retval
=
mg_write
(
conn
,
copy
,
copy_len
);
}
free
(
copy
);
return
retval
;
}
#endif // !USE_WEBSOCKET
mongoose.c
View file @
988b40f7
...
...
@@ -495,6 +495,10 @@ static void sockaddr_to_string(char *buf, size_t len,
#endif
}
static
void
gmt_time_string
(
char
*
buf
,
size_t
buf_len
,
time_t
*
t
)
{
strftime
(
buf
,
buf_len
,
"%a, %d %b %Y %H:%M:%S GMT"
,
gmtime
(
t
));
}
static
void
mg_strlcpy
(
register
char
*
dst
,
register
const
char
*
src
,
size_t
n
)
{
for
(;
*
src
!=
'\0'
&&
n
>
1
;
n
--
)
{
*
dst
++
=
*
src
++
;
...
...
@@ -3849,6 +3853,66 @@ int mg_websocket_write(struct mg_connection* conn, int opcode,
#endif // !USE_WEBSOCKET
// Writes PROPFIND properties for a collection element
static
void
print_props
(
struct
mg_connection
*
conn
,
const
char
*
uri
,
struct
file
*
filep
)
{
char
mtime
[
64
];
gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
filep
->
modification_time
);
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"<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
"
,
uri
,
filep
->
is_directory
?
"<d:collection/>"
:
""
,
filep
->
size
,
mtime
);
}
static
void
print_dav_dir_entry
(
struct
de
*
de
,
void
*
data
)
{
char
href
[
PATH_MAX
];
char
href_encoded
[
PATH_MAX
];
struct
mg_connection
*
conn
=
(
struct
mg_connection
*
)
data
;
mg_snprintf
(
href
,
sizeof
(
href
),
"%s%s"
,
conn
->
request_info
.
uri
,
de
->
file_name
);
mg_url_encode
(
href
,
href_encoded
,
PATH_MAX
-
1
);
print_props
(
conn
,
href_encoded
,
&
de
->
file
);
}
static
void
handle_propfind
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
const
char
*
depth
=
mg_get_header
(
conn
,
"Depth"
);
conn
->
must_close
=
1
;
conn
->
status_code
=
207
;
mg_printf
(
conn
,
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
"Content-Type: text/xml; charset=utf-8
\r\n\r\n
"
);
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?>"
"<d:multistatus xmlns:d='DAV:'>
\n
"
);
// Print properties for the requested resource itself
print_props
(
conn
,
conn
->
request_info
.
uri
,
filep
);
// If it is a directory, print directory entries too if Depth is not 0
if
(
filep
->
is_directory
&&
!
mg_strcasecmp
(
conn
->
ctx
->
config
[
ENABLE_DIRECTORY_LISTING
],
"yes"
)
&&
(
depth
==
NULL
||
strcmp
(
depth
,
"0"
)
!=
0
))
{
scan_directory
(
conn
,
path
,
conn
,
&
print_dav_dir_entry
);
}
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"%s
\n
"
,
"</d:multistatus>"
);
}
static
int
call_user
(
int
type
,
struct
mg_connection
*
conn
,
void
*
p
)
{
if
(
conn
!=
NULL
&&
conn
->
ctx
!=
NULL
)
{
conn
->
event
.
user_data
=
conn
->
ctx
->
user_data
;
...
...
@@ -4039,10 +4103,6 @@ static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
return
0
;
}
static
void
gmt_time_string
(
char
*
buf
,
size_t
buf_len
,
time_t
*
t
)
{
strftime
(
buf
,
buf_len
,
"%a, %d %b %Y %H:%M:%S GMT"
,
gmtime
(
t
));
}
static
void
construct_etag
(
char
*
buf
,
size_t
buf_len
,
const
struct
file
*
filep
)
{
snprintf
(
buf
,
buf_len
,
"
\"
%lx.%"
INT64_FMT
"
\"
"
,
...
...
@@ -4436,66 +4496,6 @@ static void handle_options_request(struct mg_connection *conn) {
mg_write
(
conn
,
reply
,
sizeof
(
reply
)
-
1
);
}
// Writes PROPFIND properties for a collection element
static
void
print_props
(
struct
mg_connection
*
conn
,
const
char
*
uri
,
struct
file
*
filep
)
{
char
mtime
[
64
];
gmt_time_string
(
mtime
,
sizeof
(
mtime
),
&
filep
->
modification_time
);
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"<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
"
,
uri
,
filep
->
is_directory
?
"<d:collection/>"
:
""
,
filep
->
size
,
mtime
);
}
static
void
print_dav_dir_entry
(
struct
de
*
de
,
void
*
data
)
{
char
href
[
PATH_MAX
];
char
href_encoded
[
PATH_MAX
];
struct
mg_connection
*
conn
=
(
struct
mg_connection
*
)
data
;
mg_snprintf
(
href
,
sizeof
(
href
),
"%s%s"
,
conn
->
request_info
.
uri
,
de
->
file_name
);
mg_url_encode
(
href
,
href_encoded
,
PATH_MAX
-
1
);
print_props
(
conn
,
href_encoded
,
&
de
->
file
);
}
static
void
handle_propfind
(
struct
mg_connection
*
conn
,
const
char
*
path
,
struct
file
*
filep
)
{
const
char
*
depth
=
mg_get_header
(
conn
,
"Depth"
);
conn
->
must_close
=
1
;
conn
->
status_code
=
207
;
mg_printf
(
conn
,
"HTTP/1.1 207 Multi-Status
\r\n
"
"Connection: close
\r\n
"
"Content-Type: text/xml; charset=utf-8
\r\n\r\n
"
);
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?>"
"<d:multistatus xmlns:d='DAV:'>
\n
"
);
// Print properties for the requested resource itself
print_props
(
conn
,
conn
->
request_info
.
uri
,
filep
);
// If it is a directory, print directory entries too if Depth is not 0
if
(
filep
->
is_directory
&&
!
mg_strcasecmp
(
conn
->
ctx
->
config
[
ENABLE_DIRECTORY_LISTING
],
"yes"
)
&&
(
depth
==
NULL
||
strcmp
(
depth
,
"0"
)
!=
0
))
{
scan_directory
(
conn
,
path
,
conn
,
&
print_dav_dir_entry
);
}
conn
->
num_bytes_sent
+=
mg_printf
(
conn
,
"%s
\n
"
,
"</d:multistatus>"
);
}
static
int
isbyte
(
int
n
)
{
return
n
>=
0
&&
n
<=
255
;
}
...
...
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