Roxen.git
/
server
/
base_server
/
prototypes.pike
version
»
Context lines:
10
20
40
80
file
none
3
Roxen.git/server/base_server/prototypes.pike:1967:
//! //! As @rfc{4918:10.4.1@} states that the mere fact that a state //! token appears in an If header means that it has been submitted, //! we as a convenience add all non-negated lock tokens to the //! @expr{0@} resource. //! //! @seealso //! @rfc{4918:10.4.2@} mapping(string:array(array(array(string)))) get_if_data() {
+
string read_until(Stdio.Buffer buf, int term)
+
{
+
string res = "";
+
while (sizeof(buf) && (buf[0] != term)) {
+
res += buf->read(1);
+
}
+
if (sizeof(buf)) buf->consume(1);
+
return res;
+
};
+
+
string read_quoted_until(Stdio.Buffer buf, int term)
+
{
+
string res = "";
+
while (sizeof(buf) && (buf[0] != term)) {
+
if (buf[0] == '\\') {
+
// FIXME: Should we keep the escape character or not?
+
// Currently this function is only used for reading
+
// etags, including the surrounding double quotes,
+
// so it seems reasonable to also keep the escapes.
+
res += buf->read(2);
+
} else {
+
res += buf->read(1);
+
}
+
}
+
if (sizeof(buf)) buf->consume(1);
+
return res;
+
};
+
if (if_data) { IF_HDR_MSG ("get_if_data(): Returning cached result\n"); return sizeof(if_data) && if_data; } if_data = ([]); // Negative caching. string raw_header; if (!(raw_header = request_headers->if)) { IF_HDR_MSG ("get_if_data(): No if header\n"); return 0; }
-
array(array(string|int|array(array(string)))) decoded_if =
-
MIME.decode_words_tokenized_labled(raw_header);
-
-
#if 0
-
IF_HDR_MSG("get_if_data(): decoded_if: %O\n", decoded_if);
-
#endif
-
-
if (!sizeof(decoded_if)) {
-
IF_HDR_MSG("Got only whitespace.\n");
-
return 0;
-
}
-
+
mapping(string:array(array(array(string)))) res = ([ 0:({}), ]); array(string) keys = ({});
-
string tmp_resource;
+
string resource = not_query;
-
foreach
(
decoded
_
if,
array
(
string|int|array
(
array(string
))
)
symbol)
{
-
switch
(
symbol
[0]) {
-
case
"special"
:
-
switch(symbol[1])
{
-
case '
<
':
tmp_resource
=
"";
break
;
-
case '
>
':
-
resource
=
tmp_resource
;
-
tmp_
resource =
0
;
+
+
Stdio.Buffer raw = Stdio.Buffer
(
raw
_
header);
+
while
(
sizeof
(
raw
)) {
+
switch(
raw
[0]) {
+
case
' '
:
case
'\t':
//
LWS
+
case
'\r':
case '
\n
':
+
raw->consume(1)
;
+
continue;
+
case '
<
':
// Resource-Tag
+
{
+
raw->consume(1)
;
+
resource =
read_until(raw, '>')
;
// Normalize. // FIXME: Check that the protocol and server parts refer // to this server. // NB: Above invalid according to rfc 4918 8.3. // // NB: RFC 4918 8.3 adds support for path-absolute resources. // NB: The resource reference may have a query section. // // FIXME: Support for servers mounted on subpaths. catch { resource = Standards.URI(resource)->path; }; catch { resource = Protocols.HTTP.percent_decode(resource); }; catch { resource = utf8_to_string(resource); }; resource = Unicode.normalize(resource, "NFC"); if (!sizeof(resource)) resource = "/"; if (!res[resource]) res[resource] = ({}); break;
-
default:
-
if (tmp_resource) tmp_resource += sprintf("%c", symbol[1]);
-
break;
+
}
-
break;
-
case
"word":
-
case "domain-literal":
-
// Resource
-
if
(
!tmp_resource) return 0;
-
tmp_resource += symbol[1];
-
break;
-
case "comment"
:
+
case
'
(
'
:
// Parenthesis expression.
-
if
(
tmp_resource) {
-
// Inside a resource.
-
tmp_resource += "(" + symbol[
1
][0][0] + "
)
"
;
-
break;
-
}
-
array(array(string|int|array(array(string)))) sub_expr =
-
MIME.decode_words_tokenized_labled(symbol[1][0][0]);
-
int i;
+
raw->consume
(1);
array(array(string)) expr = ({});
-
string
tmp_key;
-
for
(
i = 0; i <
sizeof(
sub_expr
)
; i++
) {
-
switch(
sub_expr
[
i][
0]) {
-
case
"special"
:
-
switch
(
sub_expr[i][
1
]
)
{
-
case '
<
':
tmp_key
=
"";
break;
-
case '
>
':
-
if
(!tmp_key)
{
-
IF_HDR_MSG("No
tmp_key.\n");
-
return
0
;
-
}
+
while
(sizeof(
raw
)) {
+
switch(
raw
[0]) {
+
case
')'
:
+
raw->consume
(1)
;
+
break;
+
case
'
':
case '
\t
':
//
LWS
+
case
'\r':
case '
\n
':
+
raw->consume(1);
+
continue;
+
case
'<':
//
State-token
+
{
+
raw->consume(1)
;
+
string tmp_key = read_until(raw, '>');
if (!sizeof(expr) || (expr[-1][0] != "not")) { keys += ({ tmp_key }); } expr += ({ ({ "key", tmp_key }) });
-
tmp_key = 0
;
-
break;
-
default:
-
if (tmp_key) tmp_key += sprintf("%c", sub_expr[i][1]);
-
break;
+
continue
;
}
-
break;
-
case
"domain-literal":
-
if (tmp_key) {
-
tmp_key += sub_expr
[
i][1];
-
break;
-
}
+
case
'['
:
// entity-tag.
-
string etag = sub_expr[i][
1
]
;
-
//
etag
is
usually something like "[\"some etag\"]" here.
-
sscanf
(
etag
,
"[%s
]
", etag
);
// Remove brackets
+
raw->consume(
1
)
;
+
string
etag
=
read_quoted_until
(
raw
,
'
]
'
);
expr += ({ ({ "etag", etag }) });
-
break
;
-
case "word"
:
-
//
State-token
or
Not.
-
if
(
tmp_key
)
{
-
tmp_key += sub_expr[i][1]
;
-
break;
-
}
-
if (lower_case(
sub_expr[i][1]
) == "not") {
+
continue
;
+
default
:
+
string
not
=
raw->read
(
3
);
+
if (lower_case(
not
) == "not") {
// Not if (sizeof(expr) && (expr[-1][0] == "not")) { IF_HDR_MSG("Double negation."); report_debug("Syntax error in if-header: %O\n", raw_header); return 0; } expr += ({ ({ "not", 0 }) }); break; }
-
IF_HDR_MSG("Word outside key: %O\n",
sub_expr[i][1]
);
+
IF_HDR_MSG("Word outside key: %O\n",
not
);
report_debug("Syntax error in if-header: %O\n", raw_header); return 0; } }
-
if (tmp_key) {
-
IF_HDR_MSG("Active tmp_key: %O\n", tmp_key);
-
report_debug("Syntax error in if-header: %O\n", raw_header);
-
return 0;
-
}
+
res[resource] += ({ expr }); break; default:
-
+
IF_HDR_MSG("Unexpected character: '%c' (raw: %O)\n", raw[0], raw);
report_debug("Syntax error in if-header: %O\n", raw_header); return 0; } }
-
+
+
if (sizeof(res) <= 1) {
+
IF_HDR_MSG("Got only whitespace.\n");
+
return 0;
+
}
+
if (sizeof(keys)) { res[0] = ({ map(keys, lambda(string key) { return ({ "key", key }); }), }); }
-
if (tmp_resource) {
-
IF_HDR_MSG("Active tmp_resource: %O\n", tmp_resource);
-
report_debug("Syntax error in if-header: %O\n", raw_header);
-
return 0;
-
}
+
IF_HDR_MSG("get_if_data(): Parsed if header: %s:\n" "%O\n", raw_header, res); return if_data = res; } int get_max_cache() //! Returns the maximum cacheable time in seconds. See //! @expr{@[misc]->cacheable@}. { return misc->cacheable;
Roxen.git/server/base_server/prototypes.pike:2553:
string scheme = find_in_misc_forwarded("proto", true); if (!scheme) { scheme = port_obj?->prot_name; } if (scheme) { scheme = lower_case(scheme); } return scheme; }
-
protected
string cached_url_base;
+
string cached_url_base;
string url_base() //! Returns the base part of the URL, i.e. what should be added in //! front of a path in the virtual filesystem to get the absolute //! URL to the page. The returned string ends with a "/", or is "" //! if no server base could be found. //! //! This function gets the correct host for protocols that handles //! IP-less hosts. {
Roxen.git/server/base_server/prototypes.pike:4249:
mapping(string:mixed) make_collection(string path, RequestID id); mapping(string:mixed) recurse_copy_files(string source, string destination, PropertyBehavior behavior, Overwrite overwrite, RequestID id, int|void one_level); mapping(string:mixed) recurse_move_files(string source, string destination, PropertyBehavior behavior, Overwrite overwrite, RequestID id); }
+
//! @appears WebSocketAPI
+
//! API used by websockets.
+
//!
+
//! An object implementing this class is passed to
+
//! @[Roxen.upgrade_to_websocket()].
+
class WebSocketAPI
+
{
+
//! @decl void websocket_ready(WebSocket ws)
+
//!
+
//! Callback called when the websocket connection has been setup and
+
//! we are ready to send messages across the connection.
+
//!
+
//! @param ws
+
//! @[WebSocket] for the new connection.
+
void websocket_ready(Protocols.WebSocket.Connection ws);
+
+
//! @decl void websocket_message(WebSocket ws, @
+
//! Protocols.WebSocket.Frame frame)
+
//!
+
//! Callback called when a webscoket message has arrived.
+
//!
+
//! @param ws
+
//! @[WebSocket] on which the message arrived.
+
//!
+
//! @param frame
+
//! Websocket message.
+
void websocket_message(Protocols.WebSocket.Connection ws,
+
Protocols.WebSocket.Frame frame);
+
+
//! @decl void websocket_close(WebSocket ws, @
+
//! Protocols.WebSocket.CLOSE_STATUS reason)
+
//!
+
//! Called when a websocket connection is being closed.
+
//!
+
//! @param ws
+
//! @[WebSocket] that is being closed.
+
//!
+
//! @param reason
+
//! Reason code for what has triggered the close.
+
//!
+
//! @note
+
//! Will be called even when this side has ended the connection
+
//! by calling @[WebSocket()->websocket_close()] in @[ws].
+
void websocket_close(Protocols.WebSocket.Connection ws,
+
Protocols.WebSocket.CLOSE_STATUS reason);
+
}
+
class PatchPropertyCommand { constant command = ""; string property_name; mapping(string:mixed) execute(PropertySet context); } class _roxen { mapping(string:object) variables;