static ngx_int_t
ngx_http_foo_header_filter(ngx_http_request_t *r)
{
    ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, "Header filter add header");
    ngx_table_elt_t  *h;

    /*
     * The filter handler adds "X-Foo: foo" header
     * to every HTTP 200 response
     */

    if (r->headers_out.status != NGX_HTTP_OK) {
        return ngx_http_next_header_filter(r);
    }

    h = ngx_list_push(&r->headers_out.headers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    h->hash = 1;
    ngx_str_set(&h->key, "X-Foo");
    ngx_str_set(&h->value, "foo");

    ngx_http_clear_content_length(r);
    ngx_http_clear_accept_ranges(r);
    ngx_http_weak_etag(r);

    return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_addition_header_filter(ngx_http_request_t *r)
{
    ngx_http_addition_ctx_t   *ctx;
    ngx_http_addition_conf_t  *conf;

    if (r->headers_out.status != NGX_HTTP_OK || r != r->main) {
        return ngx_http_next_header_filter(r);
    }

    conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);

    if (conf->before_body.len == 0 && conf->after_body.len == 0) {
        return ngx_http_next_header_filter(r);
    }

    if (ngx_http_test_content_type(r, &conf->types) == NULL) {
        return ngx_http_next_header_filter(r);
    }

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_addition_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_http_set_ctx(r, ctx, ngx_http_addition_filter_module);

    ngx_http_clear_content_length(r);
    ngx_http_clear_accept_ranges(r);
    ngx_http_weak_etag(r);

    return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_gunzip_header_filter(ngx_http_request_t *r)
{
    ngx_http_gunzip_ctx_t   *ctx;
    ngx_http_gunzip_conf_t  *conf;

    conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module);

    /* TODO support multiple content-codings */
    /* TODO ignore content encoding? */

    if (conf->enable == NGX_HTTP_GUNZIP_OFF
        || r->headers_out.content_encoding == NULL
        || r->headers_out.content_encoding->value.len != 4
        || ngx_strncasecmp(r->headers_out.content_encoding->value.data,
                           (u_char *) "gzip", 4) != 0)
    {
        return ngx_http_next_header_filter(r);
    }

    r->gzip_vary = 1;

    if (conf->enable == NGX_HTTP_GUNZIP_ON) {
        if (!r->gzip_tested) {
            if (ngx_http_gzip_ok(r) == NGX_OK) {
                return ngx_http_next_header_filter(r);
            }

        } else if (r->gzip_ok) {
                   return ngx_http_next_header_filter(r);
        }

    } else if (conf->enable == NGX_HTTP_GUNZIP_ALWAYS
               && ngx_http_test_content_type(r, &conf->types) == NULL)
    {
               return ngx_http_next_header_filter(r);
    }

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gunzip_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ngx_http_set_ctx(r, ctx, ngx_http_gunzip_filter_module);

    ctx->request = r;

    r->filter_need_in_memory = 1;

    r->headers_out.content_encoding->hash = 0;
    r->headers_out.content_encoding = NULL;

    ngx_http_clear_content_length(r);
    ngx_http_clear_accept_ranges(r);
    ngx_http_weak_etag(r);

    return ngx_http_next_header_filter(r);
}
Пример #4
0
static ngx_int_t
ngx_http_sub_header_filter(ngx_http_request_t *r)
{
    ngx_http_sub_ctx_t        *ctx;
    ngx_http_sub_loc_conf_t  *slcf;

    slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);

    if (slcf->match.len == 0
        || r->headers_out.content_length_n == 0
        || ngx_http_test_content_type(r, &slcf->types) == NULL)
    {
        return ngx_http_next_header_filter(r);
    }

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    ctx->saved.data = ngx_pnalloc(r->pool, slcf->match.len);
    if (ctx->saved.data == NULL) {
        return NGX_ERROR;
    }

    ctx->looked.data = ngx_pnalloc(r->pool, slcf->match.len);
    if (ctx->looked.data == NULL) {
        return NGX_ERROR;
    }

    ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);

    ctx->match = slcf->match;
    ctx->last_out = &ctx->out;

    r->filter_need_in_memory = 1;

    if (r == r->main) {
        ngx_http_clear_content_length(r);

        if (!slcf->last_modified) {
            ngx_http_clear_last_modified(r);
            ngx_http_clear_etag(r);

        } else {
            ngx_http_weak_etag(r);
        }
    }

    return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_brotli_header_filter(ngx_http_request_t *r)
{
    ngx_table_elt_t         *h;
    ngx_http_brotli_ctx_t   *ctx;
    ngx_http_brotli_conf_t  *conf;

    conf = ngx_http_get_module_loc_conf(r, ngx_http_brotli_filter_module);

    if (!conf->enable
        || (r->headers_out.status != NGX_HTTP_OK
            && r->headers_out.status != NGX_HTTP_FORBIDDEN
            && r->headers_out.status != NGX_HTTP_NOT_FOUND)
        || (r->headers_out.content_length_n != -1
            && r->headers_out.content_length_n < conf->min_length)
        || ngx_http_test_content_type(r, &conf->types) == NULL
        || r->header_only)
    {
        return ngx_http_next_header_filter(r);
    }

    if (r->headers_out.content_encoding
        && r->headers_out.content_encoding->value.len)
    {
        return ngx_http_next_header_filter(r);
    }

    /* Check that brotli is supported. We do not check possible q value
     * if brotli is supported it takes precendence over gzip if size >
     * brotli_min_length */
    if (accept_br(r->headers_in.accept_encoding) != NGX_OK) {
        return ngx_http_next_header_filter(r);
    }

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_brotli_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }

#if (NGX_HTTP_GZIP)
    r->gzip_vary = 1;
    /* Make sure gzip does not execute */
    r->gzip_tested = 1;
    r->gzip_ok = 0;
#endif

    ngx_http_set_ctx(r, ctx, ngx_http_brotli_filter_module);

    ctx->request = r;

    h = ngx_list_push(&r->headers_out.headers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    h->hash = 1;
    ngx_str_set(&h->key, "Content-Encoding");
    ngx_str_set(&h->value, "br");
    r->headers_out.content_encoding = h;

    r->main_filter_need_in_memory = 1;

    ngx_http_clear_content_length(r);
    ngx_http_clear_accept_ranges(r);
    ngx_http_weak_etag(r);

    return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_concat_handler(ngx_http_request_t *r)
{
    off_t                       length;
    size_t                      root, last_len;
    time_t                      last_modified;
    u_char                     *p, *v, *e, *last, *last_type;
    ngx_int_t                   rc;
    ngx_str_t                  *uri, *filename, path;
    ngx_buf_t                  *b;
    ngx_uint_t                  i, j, level;
    ngx_flag_t                  timestamp;
    ngx_array_t                 uris;
    ngx_chain_t                 out, **last_out, *cl;
    ngx_open_file_info_t        of;
    ngx_http_core_loc_conf_t   *ccf;
    ngx_http_concat_loc_conf_t *clcf;

    if (r->uri.data[r->uri.len - 1] != '/') {
        return NGX_DECLINED;
    }

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_DECLINED;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_concat_module);

    if (!clcf->enable) {
        return NGX_DECLINED;
    }

    /* the length of args must be greater than or equal to 2 */
    if (r->args.len < 2 || r->args.data[0] != '?') {
        return NGX_DECLINED;
    }

    rc = ngx_http_discard_request_body(r);

    if (rc != NGX_OK) {
        return rc;
    }

    last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    if (last == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    path.len = last - path.data;

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http concat root: \"%V\"", &path);

    ccf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

#if (NGX_SUPPRESS_WARN)
    ngx_memzero(&uris, sizeof(ngx_array_t));
#endif

    if (ngx_array_init(&uris, r->pool, 8, sizeof(ngx_str_t)) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    e = r->args.data + r->args.len;
    for (p = r->args.data + 1, v = p, timestamp = 0; p != e; p++) {

        if (*p == ',') {
            if (p == v || timestamp == 1) {
                v = p + 1;
                timestamp = 0;
                continue;
            }

            rc = ngx_http_concat_add_path(r, &uris, clcf->max_files, &path,
                                          p, v);
            if (rc != NGX_OK) {
                return rc;
            }

            v = p + 1;

        } else if (*p == '?') {
            if (timestamp == 1) {
                v = p;
                continue;
            }

            rc = ngx_http_concat_add_path(r, &uris, clcf->max_files, &path,
                                          p, v);
            if (rc != NGX_OK) {
                return rc;
            }

            v = p;
            timestamp = 1;
        }
    }

    if (p - v > 0 && timestamp == 0) {
        rc = ngx_http_concat_add_path(r, &uris, clcf->max_files, &path, p, v);
        if (rc != NGX_OK) {
            return rc;
        }
    }

    last_modified = 0;
    last_len = 0;
    last_out = NULL;
    b = NULL;
    last_type = NULL;
    length = 0;
    uri = uris.elts;
    for (i = 0; i < uris.nelts; i++) {
        filename = uri + i;

        for (j = filename->len - 1; j > 1; j--) {
            if (filename->data[j] == '.' && filename->data[j - 1] != '/') {

                r->exten.len = filename->len - j - 1;
                r->exten.data = &filename->data[j + 1];
                break;

            } else if (filename->data[j] == '/') {
                break;
            }
        }

        r->headers_out.content_type.len = 0;
        if (ngx_http_set_content_type(r) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        r->headers_out.content_type_lowcase = NULL;
        if (ngx_http_test_content_type(r, &clcf->types) == NULL) {
            return NGX_HTTP_BAD_REQUEST;
        }

        if (clcf->unique) { /* test if all the content types are the same */
            if ((i > 0)
                && (last_len != r->headers_out.content_type_len
                    || (last_type != NULL
                        && r->headers_out.content_type_lowcase != NULL
                        && ngx_memcmp(last_type,
                                      r->headers_out.content_type_lowcase,
                                      last_len) != 0)))
            {
                return NGX_HTTP_BAD_REQUEST;
            }

            last_len = r->headers_out.content_type_len;
            last_type = r->headers_out.content_type_lowcase;
        }

        ngx_memzero(&of, sizeof(ngx_open_file_info_t));

        of.read_ahead = ccf->read_ahead;
        of.directio = ccf->directio;
        of.valid = ccf->open_file_cache_valid;
        of.min_uses = ccf->open_file_cache_min_uses;
        of.errors = ccf->open_file_cache_errors;
        of.events = ccf->open_file_cache_events;

        if (ngx_open_cached_file(ccf->open_file_cache, filename, &of, r->pool)
            != NGX_OK)
        {
            switch (of.err) {

            case 0:
                return NGX_HTTP_INTERNAL_SERVER_ERROR;

            case NGX_ENOENT:
            case NGX_ENOTDIR:
            case NGX_ENAMETOOLONG:

                level = NGX_LOG_ERR;
                rc = NGX_HTTP_NOT_FOUND;
                break;

            case NGX_EACCES:

                level = NGX_LOG_ERR;
                rc = NGX_HTTP_FORBIDDEN;
                break;

            default:

                level = NGX_LOG_CRIT;
                rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                break;
            }

            if (rc != NGX_HTTP_NOT_FOUND || ccf->log_not_found) {
                ngx_log_error(level, r->connection->log, of.err,
                              "%s \"%V\" failed", of.failed, filename);
            }

            if (clcf->ignore_file_error
                && (rc == NGX_HTTP_NOT_FOUND || rc == NGX_HTTP_FORBIDDEN))
            {
                continue;
            }

            return rc;
        }

        if (!of.is_file) {
            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                          "\"%V\" is not a regular file", filename);
            if (clcf->ignore_file_error) {
                continue;
            }

            return NGX_HTTP_NOT_FOUND;
        }

        if (of.size == 0) {
            continue;
        }

        length += of.size;
        if (last_out == NULL) {
            last_modified = of.mtime;

        } else {
            if (of.mtime > last_modified) {
                last_modified = of.mtime;
            }
        }

        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
        if (b->file == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b->file_pos = 0;
        b->file_last = of.size;

        b->in_file = b->file_last ? 1 : 0;

        b->file->fd = of.fd;
        b->file->name = *filename;
        b->file->log = r->connection->log;

        b->file->directio = of.is_directio;

        if (last_out == NULL) {
            out.buf = b;
            last_out = &out.next;
            out.next = NULL;

        } else {
            cl = ngx_alloc_chain_link(r->pool);
            if (cl == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            cl->buf = b;

            *last_out = cl;
            last_out = &cl->next;
            cl->next = NULL;
        }

        if (i + 1 == uris.nelts || clcf->delimiter.len == 0) {
            continue;
        }

        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b->pos = clcf->delimiter.data;
        b->last = b->pos + clcf->delimiter.len;
        b->memory = 1;
        length += clcf->delimiter.len;

        cl = ngx_alloc_chain_link(r->pool);
        if (cl == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        cl->buf = b;
        *last_out = cl;
        last_out = &cl->next;
        cl->next = NULL;
    }

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = length;
    r->headers_out.last_modified_time = last_modified;

    if (ngx_http_set_etag(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    ngx_http_weak_etag(r);

    if (b == NULL) {
        r->header_only = 1;
    }

    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }

    if (b != NULL) {
        b->last_in_chain = 1;
        b->last_buf = 1;
    }

    return ngx_http_output_filter(r, &out);
}
static ngx_buf_t *
ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
{
    int                            sx, sy, dx, dy, ox, oy, ax, ay, size,
                                   colors, palette, transparent, sharpen,
                                   red, green, blue, t;
    u_char                        *out;
    ngx_buf_t                     *b;
    ngx_uint_t                     resize;
    gdImagePtr                     src, dst;
    ngx_pool_cleanup_t            *cln;
    ngx_http_image_filter_conf_t  *conf;

    src = ngx_http_image_source(r, ctx);

    if (src == NULL) {
        return NULL;
    }

    sx = gdImageSX(src);
    sy = gdImageSY(src);

    conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);

    if (!ctx->force
        && ctx->angle == 0
        && (ngx_uint_t) sx <= ctx->max_width
        && (ngx_uint_t) sy <= ctx->max_height)
    {
        gdImageDestroy(src);
        return ngx_http_image_asis(r, ctx);
    }

    colors = gdImageColorsTotal(src);

    if (colors && conf->transparency) {
        transparent = gdImageGetTransparent(src);

        if (transparent != -1) {
            palette = colors;
            red = gdImageRed(src, transparent);
            green = gdImageGreen(src, transparent);
            blue = gdImageBlue(src, transparent);

            goto transparent;
        }
    }

    palette = 0;
    transparent = -1;
    red = 0;
    green = 0;
    blue = 0;

transparent:

    gdImageColorTransparent(src, -1);

    dx = sx;
    dy = sy;

    if (conf->filter == NGX_HTTP_IMAGE_RESIZE) {

        if ((ngx_uint_t) dx > ctx->max_width) {
            dy = dy * ctx->max_width / dx;
            dy = dy ? dy : 1;
            dx = ctx->max_width;
        }

        if ((ngx_uint_t) dy > ctx->max_height) {
            dx = dx * ctx->max_height / dy;
            dx = dx ? dx : 1;
            dy = ctx->max_height;
        }

        resize = 1;

    } else if (conf->filter == NGX_HTTP_IMAGE_ROTATE) {

        resize = 0;

    } else if (conf->filter == NGX_HTTP_IMAGE_WATERMARK) {

        resize = 0;

    } else { /* NGX_HTTP_IMAGE_CROP */

        resize = 0;

        if ((double) dx / dy < (double) ctx->max_width / ctx->max_height) {
            if ((ngx_uint_t) dx > ctx->max_width) {
                dy = dy * ctx->max_width / dx;
                dy = dy ? dy : 1;
                dx = ctx->max_width;
                resize = 1;
            }

        } else {
            if ((ngx_uint_t) dy > ctx->max_height) {
                dx = dx * ctx->max_height / dy;
                dx = dx ? dx : 1;
                dy = ctx->max_height;
                resize = 1;
            }
        }
    }

    if (resize) {
        dst = ngx_http_image_new(r, dx, dy, palette);
        if (dst == NULL) {
            gdImageDestroy(src);
            return NULL;
        }

        if (colors == 0) {
            gdImageSaveAlpha(dst, 1);
            gdImageAlphaBlending(dst, 0);
        }

        gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy);

        if (colors) {
            gdImageTrueColorToPalette(dst, 1, 256);
        }

        gdImageDestroy(src);

    } else {
        dst = src;
    }

    if (ctx->angle) {
        src = dst;

        ax = (dx % 2 == 0) ? 1 : 0;
        ay = (dy % 2 == 0) ? 1 : 0;

        switch (ctx->angle) {

        case 90:
        case 270:
            dst = ngx_http_image_new(r, dy, dx, palette);
            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }
            if (ctx->angle == 90) {
                ox = dy / 2 + ay;
                oy = dx / 2 - ax;

            } else {
                ox = dy / 2 - ay;
                oy = dx / 2 + ax;
            }

            gdImageCopyRotated(dst, src, ox, oy, 0, 0,
                               dx + ax, dy + ay, ctx->angle);
            gdImageDestroy(src);

            t = dx;
            dx = dy;
            dy = t;
            break;

        case 180:
            dst = ngx_http_image_new(r, dx, dy, palette);
            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }
            gdImageCopyRotated(dst, src, dx / 2 - ax, dy / 2 - ay, 0, 0,
                               dx + ax, dy + ay, ctx->angle);
            gdImageDestroy(src);
            break;
        }
    }

    if (conf->filter == NGX_HTTP_IMAGE_CROP) {

        src = dst;

        if ((ngx_uint_t) dx > ctx->max_width) {
            ox = dx - ctx->max_width;

        } else {
            ox = 0;
        }

        if ((ngx_uint_t) dy > ctx->max_height) {
            oy = dy - ctx->max_height;

        } else {
            oy = 0;
        }

        if (ox || oy) {

            dst = ngx_http_image_new(r, dx - ox, dy - oy, colors);

            if (dst == NULL) {
                gdImageDestroy(src);
                return NULL;
            }

            ox /= 2;
            oy /= 2;

            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "image crop: %d x %d @ %d x %d",
                           dx, dy, ox, oy);

            if (colors == 0) {
                gdImageSaveAlpha(dst, 1);
                gdImageAlphaBlending(dst, 0);
            }

            gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy);

            if (colors) {
                gdImageTrueColorToPalette(dst, 1, 256);
            }

            gdImageDestroy(src);
        }
    }

    if (transparent != -1 && colors) {
        gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue));
    }

    if (conf->filter == NGX_HTTP_IMAGE_WATERMARK && conf->watermark.data) {
        FILE *watermark_file = fopen((const char *)conf->watermark.data, "r");

        if (watermark_file) {
            gdImagePtr watermark, watermark_mix;
            ngx_int_t wdx = 0, wdy = 0;

            watermark = gdImageCreateFromPng(watermark_file);
            fclose(watermark_file);

            if(watermark != NULL) {
                watermark_mix = gdImageCreateTrueColor(watermark->sx, watermark->sy);

                if (ngx_strcmp(conf->watermark_position.data, "bottom-right") == 0) {
                    wdx = dx - watermark->sx - 10;
                    wdy = dy - watermark->sy - 10;
                } else if (ngx_strcmp(conf->watermark_position.data, "top-left") == 0) {
                    wdx = wdy = 10;
                } else if (ngx_strcmp(conf->watermark_position.data, "top-right") == 0) {
                    wdx = dx - watermark->sx - 10;
                    wdy = 10;
                } else if (ngx_strcmp(conf->watermark_position.data, "bottom-left") == 0) {
                    wdx = 10;
                    wdy = dy - watermark->sy - 10;
                } else if (ngx_strcmp(conf->watermark_position.data, "center") == 0) {
                    wdx = dx / 2 - watermark->sx / 2;
                    wdy = dy / 2 - watermark->sy / 2;
                }

                gdImageCopy(watermark_mix, dst, 0, 0, wdx, wdy, watermark->sx, watermark->sy);
                gdImageCopy(watermark_mix, watermark, 0, 0, 0, 0, watermark->sx, watermark->sy);
                gdImageCopyMerge(dst, watermark_mix, wdx, wdy, 0, 0, watermark->sx, watermark->sy, 75);
                gdImageDestroy(watermark);
                gdImageDestroy(watermark_mix);

            } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "watermark file '%s' is not PNG", conf->watermark.data);}

        } else {

            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "watermark file '%s' not found", conf->watermark.data);
        }
    }

    sharpen = ngx_http_image_filter_get_value(r, conf->shcv, conf->sharpen);
    if (sharpen > 0) {
        gdImageSharpen(dst, sharpen);
    }

    gdImageInterlace(dst, (int) conf->interlace);

    out = ngx_http_image_out(r, ctx->type, dst, &size);

    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "image: %d x %d %d", sx, sy, colors);

    gdImageDestroy(dst);
    ngx_pfree(r->pool, ctx->image);

    if (out == NULL) {
        return NULL;
    }

    cln = ngx_pool_cleanup_add(r->pool, 0);
    if (cln == NULL) {
        gdFree(out);
        return NULL;
    }

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (b == NULL) {
        gdFree(out);
        return NULL;
    }

    cln->handler = ngx_http_image_cleanup;
    cln->data = out;

    b->pos = out;
    b->last = out + size;
    b->memory = 1;
    b->last_buf = 1;

    ngx_http_image_length(r, b);
    ngx_http_weak_etag(r);

    return b;
}
static ngx_buf_t *
ngx_http_pngquant_quantize(ngx_http_request_t *r, ngx_http_pngquant_ctx_t *ctx)
{
    u_char                    *out;
    ngx_buf_t                 *b;
    ngx_pool_cleanup_t        *cln;
    ngx_http_pngquant_conf_t  *conf;
    gdImagePtr                 img;
    int                        size;

    ngx_int_t                  rc;
    ngx_temp_file_t           *tf;
    ssize_t                    n;
    ngx_ext_rename_file_t      ext;
    ngx_str_t                  dest;
    ngx_str_t                  value;


    img = gdImageCreateFromPngPtr(ctx->length, ctx->image);

    if (img == NULL) {

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
            "gdImageCreateFromPngPtr() failed");

        return NULL;
    }

    conf = ngx_http_get_module_loc_conf(r, ngx_http_pngquant_module);

    /*
     * gdImageTrueColorToPaletteSetMethod(img, GD_QUANT_LIQ, conf->speed);
     * gdImageTrueColorToPalette(img, conf->dither, conf->colors);
     */

    ngx_pngquant_gd_image(img, conf->dither, conf->colors, conf->speed);

    out = gdImagePngPtr(img, &size);

    gdImageDestroy(img);

    ngx_pfree(r->pool, ctx->image);

    if (out == NULL) {

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "gdImagePngPtr() failed");

        return NULL;
    }

    if (conf->store) {

        if(ngx_http_complex_value(r, conf->store, &value) != NGX_OK) {

            goto failed;
        }

        dest.len = value.len + 1;
        dest.data = ngx_pnalloc(r->pool, dest.len);

        if (dest.data == NULL) {

            goto failed;
        }

        ngx_memzero(dest.data, dest.len);
        ngx_memcpy(dest.data, value.data, value.len);

        ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "pngquant_store (%s)", dest.data);

        tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));

        if (tf == NULL) {

            goto failed;
        }

        tf->file.fd = NGX_INVALID_FILE;
        tf->file.log = r->connection->log;
        tf->path = conf->temp_path;
        tf->pool = r->pool;
        tf->persistent = 1;
        rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent,
                                  tf->clean, tf->access);

        if (rc != NGX_OK) {

            goto failed;
        }

        n = ngx_write_fd(tf->file.fd, out, size);

        if (n == NGX_FILE_ERROR) {

            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                          ngx_write_fd_n " \"%s\" failed", tf->file.name.data);

            goto failed;
        }

        if ((int) n != size) {

            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
                          ngx_write_fd_n " has written only %z of %uz bytes",
                          n, size);

            goto failed;
        }

        ext.access = conf->store_access;
        ext.path_access = conf->store_access;
        ext.time = -1;
        ext.create_path = 1;
        ext.delete_file = 1;
        ext.log = r->connection->log;

        rc = ngx_ext_rename_file(&tf->file.name, &dest, &ext);

        if (rc != NGX_OK) {

            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "ngx_ext_rename_file() failed");

            goto failed;
        }
    }

    cln = ngx_pool_cleanup_add(r->pool, 0);

    if (cln == NULL) {

        goto failed;
    }

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

    if (b == NULL) {

        goto failed;
    }

    cln->handler = ngx_http_pngquant_cleanup;
    cln->data = out;

    b->pos = out;
    b->last = out + size;
    b->memory = 1;
    b->last_buf = 1;

    ngx_http_pngquant_length(r, b);

#if defined(nginx_version) && (nginx_version >= 1007003)
    ngx_http_weak_etag(r);
#endif

    return b;

failed:

    gdFree(out);

    return NULL;
}
Пример #9
0
static ngx_int_t
ngx_http_sub_header_filter(ngx_http_request_t *r)
{
    ngx_str_t                *m;
    ngx_uint_t                i, j, n;
    ngx_http_sub_ctx_t       *ctx;
    ngx_http_sub_pair_t      *pairs;
    ngx_http_sub_match_t     *matches;
    ngx_http_sub_loc_conf_t  *slcf;

    slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);

    if (slcf->pairs == NULL
            || r->headers_out.content_length_n == 0
            || ngx_http_test_content_type(r, &slcf->types) == NULL)
    {
        return ngx_http_next_header_filter(r);
    }

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    if (slcf->dynamic == 0) {
        ctx->tables = slcf->tables;
        ctx->matches = slcf->matches;

    } else {
        pairs = slcf->pairs->elts;
        n = slcf->pairs->nelts;

        matches = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_match_t) * n);
        if (matches == NULL) {
            return NGX_ERROR;
        }

        j = 0;
        for (i = 0; i < n; i++) {
            matches[j].value = &pairs[i].value;

            if (pairs[i].match.lengths == NULL) {
                matches[j].match = pairs[i].match.value;
                j++;
                continue;
            }

            m = &matches[j].match;
            if (ngx_http_complex_value(r, &pairs[i].match, m) != NGX_OK) {
                return NGX_ERROR;
            }

            if (m->len == 0) {
                continue;
            }

            ngx_strlow(m->data, m->data, m->len);
            j++;
        }

        if (j == 0) {
            return ngx_http_next_header_filter(r);
        }

        ctx->matches = ngx_palloc(r->pool, sizeof(ngx_array_t));
        if (ctx->matches == NULL) {
            return NGX_ERROR;
        }

        ctx->matches->elts = matches;
        ctx->matches->nelts = j;

        ctx->tables = ngx_palloc(r->pool, sizeof(ngx_http_sub_tables_t));
        if (ctx->tables == NULL) {
            return NGX_ERROR;
        }

        ngx_http_sub_init_tables(ctx->tables, ctx->matches->elts,
                                 ctx->matches->nelts);
    }

    ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);

    ctx->saved.data = ngx_pnalloc(r->pool, ctx->tables->max_match_len - 1);
    if (ctx->saved.data == NULL) {
        return NGX_ERROR;
    }

    ctx->looked.data = ngx_pnalloc(r->pool, ctx->tables->max_match_len - 1);
    if (ctx->looked.data == NULL) {
        return NGX_ERROR;
    }

    ctx->offset = ctx->tables->min_match_len - 1;
    ctx->last_out = &ctx->out;

    r->filter_need_in_memory = 1;

    if (r == r->main) {
        ngx_http_clear_content_length(r);

        if (!slcf->last_modified) {
            ngx_http_clear_last_modified(r);
            ngx_http_clear_etag(r);

        } else {
            ngx_http_weak_etag(r);
        }
    }

    return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_brotli_header_filter(ngx_http_request_t *r)
{
    ngx_table_elt_t         *h, *ae;
    ngx_http_brotli_ctx_t   *ctx;
    ngx_http_brotli_conf_t  *conf;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http brotli header filter");

    conf = ngx_http_get_module_loc_conf(r, ngx_http_brotli_filter_module);

    if (!conf->enable
        || (r->headers_out.status != NGX_HTTP_OK
            && r->headers_out.status != NGX_HTTP_FORBIDDEN
            && r->headers_out.status != NGX_HTTP_NOT_FOUND)
        || (r->headers_out.content_encoding
            && r->headers_out.content_encoding->value.len)
        || (r->headers_out.content_length_n != -1
            && r->headers_out.content_length_n < conf->min_length)
        || ngx_http_test_content_type(r, &conf->types) == NULL
        || r->header_only)
    {
        return ngx_http_next_header_filter(r);
    }

    /* Check that brotli is supported. We do not check possible q value
     * if brotli is supported it takes precendence over gzip if size >
     * brotli_min_length */
    ae = r->headers_in.accept_encoding;
    if(!ae) {
        return ngx_http_next_header_filter(r);
    }
    /* Since there is no reason for the br string to be present
     * unless brotli is accepted either as "br" or "brotli" we
     * just check for "br" */
    if (!ngx_strstrn(ae->value.data, "br", 1)) {
        return ngx_http_next_header_filter(r);
    }

    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_brotli_ctx_t));
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    if (ngx_strstrn(ae->value.data, "brotli", 5)) {
        ctx->br = 0;
    } else {
        ctx->br = 1;
    }
#if (NGX_HTTP_GZIP)
    r->gzip_vary = 1;
    /* Make sure gzip does not execute */
    r->gzip_tested = 1;
    r->gzip_ok = 0;
#endif

    ngx_http_set_ctx(r, ctx, ngx_http_brotli_filter_module);

    ctx->request = r;

    h = ngx_list_push(&r->headers_out.headers);
    if (h == NULL) {
        return NGX_ERROR;
    }

    h->hash = 1;
    ngx_str_set(&h->key, "Content-Encoding");
    if (ctx->br) {
        ngx_str_set(&h->value, "br");
    } else {
        ngx_str_set(&h->value, "brotli");
    }
    r->headers_out.content_encoding = h;

    r->main_filter_need_in_memory = 1;

    ngx_http_clear_content_length(r);
    ngx_http_clear_accept_ranges(r);
    ngx_http_weak_etag(r);

    return ngx_http_next_header_filter(r);
}
static ngx_int_t
ngx_http_gzip_header_filter(ngx_http_request_t *r)
{
    ngx_table_elt_t       *h;
    ngx_http_gzip_ctx_t   *ctx;
    ngx_http_gzip_conf_t  *conf;
    conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
    if (!conf->enable
            || (r->headers_out.status != NGX_HTTP_OK
                && r->headers_out.status != NGX_HTTP_FORBIDDEN
                && r->headers_out.status != NGX_HTTP_NOT_FOUND)
            || (r->headers_out.content_encoding
                && r->headers_out.content_encoding->value.len)
            || (r->headers_out.content_length_n != -1
                && r->headers_out.content_length_n < conf->min_length)
            || ngx_http_test_content_type(r, &conf->types) == NULL
            || r->header_only)
    {
        return ngx_http_next_header_filter(r);
    }
    r->gzip_vary = 1;
#if (NGX_HTTP_DEGRADATION)
    {
        ngx_http_core_loc_conf_t  *clcf;
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
        if (clcf->gzip_disable_degradation && ngx_http_degraded(r))
        {
            return ngx_http_next_header_filter(r);
        }
    }
#endif
    if (!r->gzip_tested)
    {
        if (ngx_http_gzip_ok(r) != NGX_OK)
        {
            return ngx_http_next_header_filter(r);
        }
    }
    else if (!r->gzip_ok)
    {
        return ngx_http_next_header_filter(r);
    }
    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t));
    if (ctx == NULL)
    {
        return NGX_ERROR;
    }
    ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module);
    ctx->request = r;
    ctx->buffering = (conf->postpone_gzipping != 0);
    ngx_http_gzip_filter_memory(r, ctx);
    h = ngx_list_push(&r->headers_out.headers);
    if (h == NULL)
    {
        return NGX_ERROR;
    }
    h->hash = 1;
    ngx_str_set(&h->key, "Content-Encoding");
    ngx_str_set(&h->value, "gzip");
    r->headers_out.content_encoding = h;
    r->main_filter_need_in_memory = 1;
    ngx_http_clear_content_length(r);
    ngx_http_clear_accept_ranges(r);
    ngx_http_weak_etag(r);
    return ngx_http_next_header_filter(r);
}