Skip to content

Commit bd9dc63

Browse files
committed
use R_TopLevelExec() for server error handling
1 parent 05079c3 commit bd9dc63

File tree

3 files changed

+35
-10
lines changed

3 files changed

+35
-10
lines changed

R/server.R

+10-3
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@
3535
#' Use only in a new session. Use \sQuote{ctrl + \\} to forcibly quit
3636
#' when finished as the function blocks with no means of interruption.
3737
#'
38-
#' Currently still experimental as the server lacks error handling. Sending
39-
#' an invalid R expression will cause the server to quit.
38+
#' If the expression could not be parsed or evaluated, the response will be
39+
#' returned with a status code of 500 and a blank body.
4040
#'
4141
#' @return This function never returns.
4242
#'
4343
#' @examples
4444
#' if (interactive()) {
4545
#'
4646
#' # run server in a new session:
47-
#' # Rscript -e 'nanonext::server()'
47+
#' # Rscript -e 'nanonext::server("http://127.0.0.1:5555/api/rest")'
4848
#'
4949
#' # query using curl:
5050
#' # curl -X POST http://127.0.0.1:5555/api/rest -d 'format(Sys.time())'
@@ -55,6 +55,13 @@
5555
#' data = "format(Sys.time())"
5656
#' )
5757
#'
58+
#' # error will return status of 500
59+
#' ncurl(
60+
#' "http://127.0.0.1:5555/api/rest",
61+
#' method = "POST",
62+
#' data = "not_valid()"
63+
#' )
64+
#'
5865
#' res <- ncurl(
5966
#' "http://127.0.0.1:5555/api/rest",
6067
#' convert = FALSE,

man/server.Rd

+10-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/server.c

+15-4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,12 @@ void rest_start(void *arg) {
237237

238238
}
239239

240+
SEXP nano_eval_res;
241+
242+
void parse_eval_safe(void *data) {
243+
nano_eval_res = R_ParseEvalString((const char *) data, R_GlobalEnv);
244+
}
245+
240246
void inproc_server(const char* url) {
241247

242248
nng_socket s;
@@ -246,22 +252,27 @@ void inproc_server(const char* url) {
246252
if ((xc = nng_rep0_open(&s)) || (xc = nng_listen(s, url, NULL, 0)))
247253
fatal("unable to set up inproc", xc);
248254

255+
nano_eval_res = R_BlankScalarString;
256+
249257
for (;;) {
250258
if ((xc = nng_recvmsg(s, &msg, 0)))
251259
fatal("inproc recvmsg", xc);
252260

253261
const char *body = nng_msg_body(msg);
254262
nano_buf buf;
255-
SEXP res = R_ParseEvalString(body, R_GlobalEnv);
256-
if (TYPEOF(res) == STRSXP) {
257-
const char *string = NANO_STRING(res);
263+
264+
R_ToplevelExec(parse_eval_safe, (void *) body);
265+
266+
if (TYPEOF(nano_eval_res) == STRSXP) {
267+
const char *string = NANO_STRING(nano_eval_res);
258268
buf.buf = (unsigned char *) string;
259269
buf.cur = strlen(string);
260270
} else {
261-
nano_serialize(&buf, res, R_NilValue);
271+
nano_serialize(&buf, nano_eval_res, R_NilValue);
262272
}
263273
nng_msg_clear(msg);
264274
nng_msg_append(msg, buf.buf, buf.cur);
275+
nano_eval_res = R_BlankScalarString;
265276
if ((xc = nng_sendmsg(s, msg, 0)))
266277
fatal("inproc sendmsg", xc);
267278

0 commit comments

Comments
 (0)