~panda-roux/MoonGem

2066c5bc9dd5607791c90f6809d68844e412668a — panda-roux 5 months ago 13664c3
using a separate buffer for data written by pre-request scripts, to be written before other content (and by itself if mg.interrupt was called)
1 files changed, 41 insertions(+), 2 deletions(-)

M src/gemini.c
M src/gemini.c => src/gemini.c +41 -2
@@ 42,6 42,7 @@ typedef struct gemini_listener_t {
typedef struct context_t {
  gemini_context_t gemini;
  file_info_t file;
  struct evbuffer* early;
  struct evbuffer* out;
  SSL* ssl;
  cli_options_t* options;


@@ 81,6 82,10 @@ static void event_cb(struct bufferevent* bev, short evt, void* data) {

      evbuffer_free(ctx->out);

      if (ctx->early != NULL) {
        evbuffer_free(ctx->early);
      }

      if (ctx->file.ptr != NULL) {
        fclose(ctx->file.ptr);
      }


@@ 224,6 229,12 @@ static void send_script_response(context_t* ctx, struct bufferevent* bev) {

  // write the response header to a buffer, followed by the rendered gemtext
  write_header(ctx);

  // if the pre-request script wrote anything, then include that
  if (ctx->early != NULL) {
    evbuffer_add_buffer(ctx->out, ctx->early);
  }

  evbuffer_add_buffer(ctx->out, rendered);
  evbuffer_free(rendered);



@@ 250,17 261,43 @@ static void send_file_response(context_t* ctx, struct bufferevent* bev) {

  // write response header
  write_header(ctx);

  // if the pre-request script wrote anything, then include that
  if (ctx->early != NULL) {
    evbuffer_add_buffer(ctx->out, ctx->early);
  }

  bufferevent_write_buffer(bev, ctx->out);

  // serve the file
  bufferevent_setcb(bev, NULL, serve_static_file_cb, event_cb, ctx);
}

static void send_early_response(context_t* ctx, struct bufferevent* bev) {
  if (ctx->early == NULL) {
    return;
  }

  LOG_DEBUG("Pre-request script bypassed the rest of the response pipeline");

  // write response header
  write_header(ctx);

  // all we should have is the pre-response script's output buffer, so just
  // write that and end the response
  evbuffer_add_buffer(ctx->out, ctx->early);

  bufferevent_write_buffer(bev, ctx->out);
  bufferevent_setcb(bev, NULL, end_response_cb, event_cb, ctx);
}

static void write_response_cb(struct bufferevent* bev, void* data) {
  context_t* ctx = (context_t*)data;

  if (ctx->gemini.response.status == STATUS_DEFAULT) {
    if (ctx->gemini.request.uri->type == URI_TYPE_GEMTEXT) {
    if (ctx->gemini.response.interrupted) {
      send_early_response(ctx, bev);
    } else if (ctx->gemini.request.uri->type == URI_TYPE_GEMTEXT) {
      send_script_response(ctx, bev);
    } else {
      send_file_response(ctx, bev);


@@ 299,8 336,9 @@ static void read_cb(struct bufferevent* bev, void* data) {
    bool pre_script_failed = false;
    if (options->pre_script_path != NULL) {
      ctx->script_ctx = create_script_ctx(&ctx->gemini);
      ctx->early = evbuffer_new();
      if (exec_script_file(ctx->script_ctx, options->pre_script_path,
                           ctx->out) != SCRIPT_OK) {
                           ctx->early) != SCRIPT_OK) {
        pre_script_failed = true;
        set_response_status(res, STATUS_CGI_ERROR, META_CGI_ERROR);
        LOG_ERROR(


@@ 366,6 404,7 @@ static void listener_cb(struct evconnlistener* listener, evutil_socket_t fd,
  ctx->magic = gemini->magic;
  ctx->options = gemini->options;
  ctx->script_ctx = NULL;
  ctx->early = NULL;

  bufferevent_setcb(bev, read_cb, NULL, event_cb, ctx);
  bufferevent_enable(bev, EV_READ);