ngx_http_qjs_ext_send_buffer(JSContext *cx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
+ size_t byte_offset, byte_length, len;
unsigned last_buf, flush;
- JSValue flags, value;
+ JSValue flags, value, val, buf;
ngx_str_t buffer;
ngx_buf_t *b;
+ const char *str;
ngx_chain_t *cl;
ngx_http_js_ctx_t *ctx;
ngx_http_request_t *r;
return JS_ThrowTypeError(cx, "cannot send buffer while not filtering");
}
- if (ngx_qjs_string(cx, argv[0], &buffer) != NGX_OK) {
- return JS_ThrowTypeError(cx, "failed get buffer arg");
- }
-
flush = ctx->buf->flush;
last_buf = ctx->buf->last_buf;
JS_FreeValue(cx, value);
}
- cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
- if (cl == NULL) {
- return JS_ThrowOutOfMemory(cx);
+ val = argv[0];
+
+ if (JS_IsNullOrUndefined(val)) {
+ buffer.len = 0;
+ buffer.data = NULL;
}
- b = cl->buf;
+ str = NULL;
+ buf = JS_UNDEFINED;
- b->flush = flush;
- b->last_buf = last_buf;
+ if (JS_IsString(val)) {
+ goto string;
+ }
- b->memory = (buffer.len ? 1 : 0);
- b->sync = (buffer.len ? 0 : 1);
- b->tag = (ngx_buf_tag_t) &ngx_http_js_module;
+ buf = JS_GetTypedArrayBuffer(cx, val, &byte_offset, &byte_length, NULL);
+ if (!JS_IsException(buf)) {
+ buffer.data = JS_GetArrayBuffer(cx, &buffer.len, buf);
+ if (buffer.data == NULL) {
+ JS_FreeValue(cx, buf);
+ return JS_EXCEPTION;
+ }
- b->start = buffer.data;
- b->end = buffer.data + buffer.len;
- b->pos = b->start;
- b->last = b->end;
+ buffer.data += byte_offset;
+ buffer.len = byte_length;
- *ctx->last_out = cl;
- ctx->last_out = &cl->next;
+ } else {
+string:
+
+ str = JS_ToCStringLen(cx, &buffer.len, val);
+ if (str == NULL) {
+ return JS_EXCEPTION;
+ }
+
+ buffer.data = (u_char *) str;
+ }
+
+ do {
+ cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (cl == NULL) {
+ goto out_of_memory;
+ }
+
+ b = cl->buf;
+
+ if (b->start == NULL) {
+ b->start = ngx_pnalloc(r->pool, buffer.len);
+ if (b->start == NULL) {
+ goto out_of_memory;
+ }
+
+ len = buffer.len;
+ b->end = b->start + len;
+
+ } else {
+ len = ngx_min(buffer.len, (size_t) (b->end - b->start));
+ }
+
+ memcpy(b->start, buffer.data, len);
+
+ b->pos = b->start;
+ b->last = b->start + len;
+
+ if (buffer.len == len) {
+ b->last_buf = last_buf;
+ b->flush = flush;
+
+ } else {
+ b->last_buf = 0;
+ b->flush = 0;
+ }
+
+ b->memory = (len ? 1 : 0);
+ b->sync = (len ? 0 : 1);
+ b->tag = (ngx_buf_tag_t) &ngx_http_js_module;
+
+ buffer.data += len;
+ buffer.len -= len;
+
+ *ctx->last_out = cl;
+ ctx->last_out = &cl->next;
+
+ } while (buffer.len != 0);
+
+ if (str != NULL) {
+ JS_FreeCString(cx, str);
+ }
+
+ JS_FreeValue(cx, buf);
return JS_UNDEFINED;
+
+out_of_memory:
+
+ if (str != NULL) {
+ JS_FreeCString(cx, str);
+ }
+
+ JS_FreeValue(cx, buf);
+
+ return JS_ThrowOutOfMemory(cx);
}
ngx_stream_qjs_ext_send(JSContext *cx, JSValueConst this_val, int argc,
JSValueConst *argv, int from_upstream)
{
- JSValue val;
+ size_t byte_offset, byte_length, len;
+ JSValue val, buf;
unsigned last_buf, flush;
ngx_str_t buffer;
ngx_buf_t *b;
+ const char *str;
ngx_chain_t *cl;
ngx_connection_t *c;
ngx_stream_js_ctx_t *ctx;
return JS_ThrowInternalError(cx, "cannot send buffer in this handler");
}
- if (ngx_qjs_string(cx, argv[0], &buffer) != NGX_OK) {
- return JS_EXCEPTION;
- }
-
/*
* ctx->buf != NULL when s.send() is called while processing incoming
* data chunks, otherwise s.send() is called asynchronously
}
}
- cl = ngx_chain_get_free_buf(c->pool, &ctx->free);
- if (cl == NULL) {
- return JS_ThrowInternalError(cx, "memory error");
+ val = argv[0];
+
+ if (JS_IsNullOrUndefined(val)) {
+ buffer.len = 0;
+ buffer.data = NULL;
}
- b = cl->buf;
+ str = NULL;
+ buf = JS_UNDEFINED;
- b->flush = flush;
- b->last_buf = last_buf;
+ if (JS_IsString(val)) {
+ goto string;
+ }
- b->memory = (buffer.len ? 1 : 0);
- b->sync = (buffer.len ? 0 : 1);
- b->tag = (ngx_buf_tag_t) &ngx_stream_js_module;
+ buf = JS_GetTypedArrayBuffer(cx, val, &byte_offset, &byte_length, NULL);
+ if (!JS_IsException(buf)) {
+ buffer.data = JS_GetArrayBuffer(cx, &buffer.len, buf);
+ if (buffer.data == NULL) {
+ JS_FreeValue(cx, buf);
+ return JS_EXCEPTION;
+ }
- b->start = buffer.data;
- b->end = buffer.data + buffer.len;
+ buffer.data += byte_offset;
+ buffer.len = byte_length;
- b->pos = b->start;
- b->last = b->end;
+ } else {
+string:
- if (from_upstream == NGX_JS_BOOL_UNSET) {
- *ctx->last_out = cl;
- ctx->last_out = &cl->next;
+ str = JS_ToCStringLen(cx, &buffer.len, val);
+ if (str == NULL) {
+ return JS_EXCEPTION;
+ }
- } else {
+ buffer.data = (u_char *) str;
+ }
- if (ngx_stream_js_next_filter(s, ctx, cl, from_upstream) == NGX_ERROR) {
- return JS_ThrowInternalError(cx, "ngx_stream_js_next_filter() "
- "failed");
+ do {
+ cl = ngx_chain_get_free_buf(c->pool, &ctx->free);
+ if (cl == NULL) {
+ goto out_of_memory;
+ }
+
+ b = cl->buf;
+
+ if (b->start == NULL) {
+ b->start = ngx_pnalloc(c->pool, buffer.len);
+ if (b->start == NULL) {
+ goto out_of_memory;
+ }
+
+ len = buffer.len;
+ b->end = b->start + len;
+
+ } else {
+ len = ngx_min(buffer.len, (size_t) (b->end - b->start));
+ }
+
+ memcpy(b->start, buffer.data, len);
+
+ b->pos = b->start;
+ b->last = b->start + len;
+
+ if (buffer.len == len) {
+ b->last_buf = last_buf;
+ b->flush = flush;
+
+ } else {
+ b->last_buf = 0;
+ b->flush = 0;
}
+
+ b->memory = (len ? 1 : 0);
+ b->sync = (len ? 0 : 1);
+ b->tag = (ngx_buf_tag_t) &ngx_stream_js_module;
+
+ buffer.data += len;
+ buffer.len -= len;
+
+ if (from_upstream == NGX_JS_BOOL_UNSET) {
+ *ctx->last_out = cl;
+ ctx->last_out = &cl->next;
+
+ } else {
+
+ if (ngx_stream_js_next_filter(s, ctx, cl, from_upstream)
+ == NGX_ERROR)
+ {
+ if (str != NULL) {
+ JS_FreeCString(cx, str);
+ }
+
+ return JS_ThrowInternalError(cx, "ngx_stream_js_next_filter() "
+ "failed");
+ }
+ }
+
+ } while (buffer.len != 0);
+
+ if (str != NULL) {
+ JS_FreeCString(cx, str);
}
+ JS_FreeValue(cx, buf);
+
return JS_UNDEFINED;
+
+out_of_memory:
+
+ if (str != NULL) {
+ JS_FreeCString(cx, str);
+ }
+
+ JS_FreeValue(cx, buf);
+
+ return JS_ThrowInternalError(cx, "memory error");
}