예제 #1
0
ngx_http_variable_value_t *
ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
{
    ngx_http_variable_t        *v;
    ngx_http_variable_value_t  *vv;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
	//先根据哈希表查找变量是否存在,如果存在,则根据其保存在哈希表里面的index获取变量的内容。或者调用get_handler
    v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
    if (v) {
        if (v->flags & NGX_HTTP_VAR_INDEXED) {
            return ngx_http_get_flushed_variable(r, v->index);
        } else {
            vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
            if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
                return vv;
            }
            return NULL;
        }
    }
	//如果不存在variables里面,则看一下是否是预定义的变量。
    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
    if (vv == NULL) {
        return NULL;
    }
    if (ngx_strncmp(name->data, "http_", 5) == 0) {
        if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name) == NGX_OK){
            return vv;
        }
        return NULL;
    }
    if (ngx_strncmp(name->data, "sent_http_", 10) == 0) {
        if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name)  == NGX_OK)  {
            return vv;
        }
        return NULL;
    }
    if (ngx_strncmp(name->data, "upstream_http_", 14) == 0) {
        if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name) == NGX_OK) {
            return vv;
        }
        return NULL;
    }
    if (ngx_strncmp(name->data, "cookie_", 7) == 0) {
        if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) {
            return vv;
        }
        return NULL;
    }
    if (ngx_strncmp(name->data, "arg_", 4) == 0) {
        if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
            return vv;
        }
        return NULL;
    }
    vv->not_found = 1;
    return vv;
}
예제 #2
0
static ngx_int_t
ngx_http_zip_main_request_header_filter(ngx_http_request_t *r)
{
    ngx_http_variable_value_t  *vv;
    ngx_http_zip_ctx_t         *ctx;

    if ((ctx = ngx_http_get_module_ctx(r, ngx_http_zip_module)) != NULL)
        return ngx_http_next_header_filter(r);

    if ((vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t))) == NULL) 
        return NGX_ERROR;
  
    /* Look for X-Archive-Files */
    ngx_int_t variable_header_status = NGX_OK;
    if (r->upstream) {
        variable_header_status = ngx_http_upstream_header_variable(r, vv, 
                (uintptr_t)(&ngx_http_zip_header_variable_name));
    } else if (r->headers_out.status == NGX_HTTP_OK) {
        variable_header_status = ngx_http_variable_unknown_header(vv, 
                &ngx_http_zip_header_variable_name,
                &r->headers_out.headers.part, sizeof("upstream_http_") - 1); 
    } else {
        vv->not_found = 1;
    }

    if (variable_header_status != NGX_OK || vv->not_found || 
            ngx_strncmp(vv->data, "zip", sizeof("zip") - 1) != 0) {
        return ngx_http_next_header_filter(r);
    }
    
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mod_zip: X-Archive-Files found");

    if ((ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_zip_ctx_t))) == NULL 
        || ngx_array_init(&ctx->files, r->pool, 1, sizeof(ngx_http_zip_file_t)) == NGX_ERROR
        || ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_zip_range_t)) == NGX_ERROR)
        return NGX_ERROR;
    
    ngx_http_set_ctx(r, ctx, ngx_http_zip_module);

    return NGX_OK;
}
예제 #3
0
ngx_http_variable_value_t *
ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key,
    ngx_uint_t nowarn)
{
    ngx_http_variable_t        *v;
    ngx_http_variable_value_t  *vv;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

    v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);

    if (v) {
        if (v->flags & NGX_HTTP_VAR_INDEXED) {
            return ngx_http_get_indexed_variable(r, v->index);

        } else {

            vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));

            if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
                return vv;
            }

            return NULL;
        }
    }

    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
    if (vv == NULL) {
        return NULL;
    }

    if (ngx_strncmp(name->data, "http_", 5) == 0) {

        if (ngx_http_variable_unknown_header_in(r, vv, (uintptr_t) name)
            == NGX_OK)
        {
            return vv;
        }

        return NULL;
    }

    if (ngx_strncmp(name->data, "sent_http_", 10) == 0) {

        if (ngx_http_variable_unknown_header_out(r, vv, (uintptr_t) name)
            == NGX_OK)
        {
            return vv;
        }

        return NULL;
    }

    if (ngx_strncmp(name->data, "upstream_http_", 10) == 0) {

        if (ngx_http_upstream_header_variable(r, vv, (uintptr_t) name)
            == NGX_OK)
        {
            return vv;
        }

        return NULL;
    }

    if (ngx_strncmp(name->data, "cookie_", 7) == 0) {

        if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) {
            return vv;
        }

        return NULL;
    }

    if (ngx_strncmp(name->data, "arg_", 4) == 0) {

        if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
            return vv;
        }

        return NULL;
    }

    vv->not_found = 1;

    if (nowarn == 0) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "unknown \"%V\" variable", name);
    }

    return vv;
}
예제 #4
0
// make our proposed ZIP-file chunk map
ngx_int_t
ngx_http_zip_generate_pieces(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx)
{
    ngx_uint_t i, piece_i;
    off_t offset = 0;
    time_t unix_time = 0;
    ngx_uint_t dos_time = 0;
    ngx_http_zip_file_t  *file;
    ngx_http_zip_piece_t *header_piece, *file_piece, *trailer_piece, *cd_piece;
    ngx_http_variable_value_t  *vv;

    if ((vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t))) == NULL)
        return NGX_ERROR;

    ctx->unicode_path = 0;
#ifdef NGX_ZIP_HAVE_ICONV
    iconv_t *iconv_cd = NULL;
#endif

    // Let's try to find special header that contains separator string.
    // What for this strange separator string you ask?
    // Sometimes there might be a problem converting UTF-8 to zips native
    // charset(CP866), because it's not 1:1 conversion. So my solution is to
    // developers provide their own version of converted filename and pass it
    // to mod_zip along with UTF-8 filename which will go straight to Unicode
    // path extra field (thanks to tony2001). So separator is a solution that doesn't
    // break current format. And allows passing file name in both formats as one string.
    //
    // Normally we pass:
    // CRC32 <size> <path> <filename>\n
    // ...
    // * <filename> passed to archive as filename w/o conversion
    // * UFT-8 flag for filename is set
    //
    // tony2001's X-Archive-Charset: <charset> way:
    // CRC32 <size> <path> <filename>\n
    // ...
    // * <filename> is accepted to be UTF-8 string
    // * <filename>, converted to <charset> and passed to archive as filename
    // * <filename> passed to Unicode path extra field
    // * UFT-8 flag for filename is not set
    //
    // My X-Archive-Name-Sep: <sep> solution:
    // CRC32 <size> <path> <native-filename><sep><utf8-filename>\n
    // ...
    // * <native-filename> passed to archive as filename w/o conversion
    // * <utf8-filename> passed to Unicode path extra field
    // * UFT-8 flag for filename is not set
    //
    // You just need to provide separator that won't interfere with file names. I suggest using '/'
    // as it is ASCII character and forbidden on most (if not all) platforms as a part of filename.
    //
    // Empty separator string means no UTF-8 version provided. Usefull when we need to pass only
    // names encoded in native charset. It's equal to 'X-Archive-Charset: native;'.
    // Note: Currently it is impossible after '[PATCH] Support for UTF-8 file names.'(4f61592b)
    // because UFT-8 flag (zip_utf8_flag) is set default for templates.

    if(ngx_http_upstream_header_variable(r, vv, (uintptr_t)(&ngx_http_zip_header_name_separator)) == NGX_OK && !vv->not_found) {
        ctx->native_charset = 1;
        if(vv->len)
            ctx->unicode_path = 1;
    } else {
#ifdef NGX_ZIP_HAVE_ICONV
        if (ngx_http_upstream_header_variable(r, vv, (uintptr_t)(&ngx_http_zip_header_charset_name)) == NGX_OK
                && !vv->not_found && ngx_strncmp(vv->data, "utf8", sizeof("utf8") - 1) != 0) {

            if(ngx_strncmp(vv->data, "native", sizeof("native") - 1))
            {
                char encoding[ICONV_CSNMAXLEN];
                snprintf(encoding, sizeof(encoding), "%s//TRANSLIT//IGNORE", vv->data);

                iconv_cd = iconv_open((const char *)encoding, "utf-8");
                if (iconv_cd == (iconv_t)(-1)) {
                    ngx_log_error(NGX_LOG_WARN, r->connection->log, errno,
                                  "mod_zip: iconv_open('%s', 'utf-8') failed",
                                  vv->data);
                    iconv_cd = NULL;
                }
                else
                {
                    ctx->unicode_path = 1;
                    ctx->native_charset = 1;
                }
            }
            else
                ctx->native_charset = 1;
        }
#endif
    }

    // pieces: for each file: header, data, footer (if needed) -> 2 or 3 per file
    // plus file footer (CD + [zip64 end + zip64 locator +] end of cd) in one chunk
    ctx->pieces_n = ctx->files.nelts * (2 + (!!ctx->missing_crc32)) + 1;

    if ((ctx->pieces = ngx_palloc(r->pool, sizeof(ngx_http_zip_piece_t) * ctx->pieces_n)) == NULL)
        return NGX_ERROR;

    ctx->cd_size = 0;
    unix_time = time(NULL);
    dos_time = ngx_dos_time(unix_time);
    for (piece_i = i = 0; i < ctx->files.nelts; i++) {
        file = &((ngx_http_zip_file_t *)ctx->files.elts)[i];
        file->offset = offset;
        file->unix_time = unix_time;
        file->dos_time = dos_time;

        if(ctx->unicode_path) {
#ifdef NGX_ZIP_HAVE_ICONV
            if (iconv_cd) {
                size_t inlen = file->filename.len, outlen, outleft;
                u_char *p, *in;

                //inbuf
                file->filename_utf8.data = ngx_pnalloc(r->pool, file->filename.len + 1);
                ngx_memcpy(file->filename_utf8.data, file->filename.data, file->filename.len);
                file->filename_utf8.len = file->filename.len;
                file->filename_utf8.data[file->filename.len] = '\0';

                //outbuf
                outlen = outleft = inlen * sizeof(int) + 15;
                file->filename.data = ngx_pnalloc(r->pool, outlen + 1);

                in = file->filename_utf8.data;
                p = file->filename.data;

                //reset state
                iconv(iconv_cd, NULL, NULL, NULL, NULL);

                //convert the string
                iconv(iconv_cd, (char **)&in, &inlen, (char **)&p, &outleft);
                //XXX if (res == (size_t)-1) { ? }

                file->filename.len = outlen - outleft;

                file->filename_utf8_crc32 = ngx_crc32_long(file->filename_utf8.data, file->filename_utf8.len);
            }
#endif
              else if(vv->len) {
                const char * sep = ngx_http_zip_strnrstr((const char*)file->filename.data, file->filename.len,
                                                         (const char*)vv->data, vv->len);
                if(sep) {
                    size_t utf8_len = file->filename.len - vv->len - (size_t)(sep - (const char *)file->filename.data);
                    file->filename_utf8.data = ngx_pnalloc(r->pool, utf8_len);
                    file->filename_utf8.len = utf8_len;
                    ngx_memcpy(file->filename_utf8.data, sep + vv->len, utf8_len);

                    file->filename.len -= utf8_len + vv->len;
                    file->filename_utf8_crc32 = ngx_crc32_long(file->filename_utf8.data, file->filename_utf8.len);
                } /* else { } */    // Separator not found. Okay, no extra field for this one then.
            }
        }

        if(offset >= (off_t) NGX_MAX_UINT32_VALUE)
            ctx->zip64_used = file->need_zip64_offset = 1;
        if(file->size >= (off_t) NGX_MAX_UINT32_VALUE)
            ctx->zip64_used = file->need_zip64 = 1;

        ctx->cd_size += sizeof(ngx_zip_central_directory_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_central_t)
            + (file->need_zip64_offset ?
                    (file->need_zip64 ? sizeof(ngx_zip_extra_field_zip64_sizes_offset_t) : sizeof(ngx_zip_extra_field_zip64_offset_only_t)) :
                    (file->need_zip64 ? sizeof(ngx_zip_extra_field_zip64_sizes_only_t) : 0) +
                    (ctx->unicode_path && file->filename_utf8.len ? (sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len): 0)
              );

        header_piece = &ctx->pieces[piece_i++];
        header_piece->type = zip_header_piece;
        header_piece->file = file;
        header_piece->range.start = offset;
        header_piece->range.end = offset += sizeof(ngx_zip_local_file_header_t)
            + file->filename.len + sizeof(ngx_zip_extra_field_local_t) + (file->need_zip64? sizeof(ngx_zip_extra_field_zip64_sizes_only_t):0)
            + (ctx->unicode_path && file->filename_utf8.len ? (sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len): 0);

        file_piece = &ctx->pieces[piece_i++];
        file_piece->type = zip_file_piece;
        file_piece->file = file;
        file_piece->range.start = offset;
        file_piece->range.end = offset += file->size; //!note: (sizeless chunks): we need file size here / or mark it and modify ranges after

        if (file->missing_crc32) { // if incomplete header -> add footer with that info to file
            trailer_piece = &ctx->pieces[piece_i++];
            trailer_piece->type = zip_trailer_piece;
            trailer_piece->file = file;
            trailer_piece->range.start = offset;
            trailer_piece->range.end = offset += file->need_zip64? sizeof(ngx_zip_data_descriptor_zip64_t) : sizeof(ngx_zip_data_descriptor_t);
            //!!TODO: if we want Ranges support - here we know it is impossible for this set
            //? check conf/some state and abort?
        }
    }

#ifdef NGX_ZIP_HAVE_ICONV
    if (iconv_cd) {
        iconv_close(iconv_cd);
    }
#endif

    ctx->zip64_used |= offset >= (off_t) NGX_MAX_UINT32_VALUE || ctx->files.nelts >= NGX_MAX_UINT16_VALUE;

    ctx->cd_size += sizeof(ngx_zip_end_of_central_directory_record_t);
    if (ctx->zip64_used)
        ctx->cd_size += sizeof(ngx_zip_zip64_end_of_central_directory_record_t) + sizeof(ngx_zip_zip64_end_of_central_directory_locator_t);


    cd_piece = &ctx->pieces[piece_i++];
    cd_piece->type = zip_central_directory_piece;
    cd_piece->range.start = offset;
    cd_piece->range.end = offset += ctx->cd_size;

    ctx->pieces_n = piece_i; //!! nasty hack (truncating allocated array without reallocation)

    ctx->archive_size = offset;

    return NGX_OK;
}
예제 #5
0
// make our proposed ZIP-file chunk map
ngx_int_t
ngx_http_zip_generate_pieces(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx)
{
    ngx_uint_t i, piece_i;
    off_t offset = 0;
    ngx_http_zip_file_t  *file;
    ngx_http_zip_piece_t *header_piece, *file_piece, *trailer_piece, *cd_piece;
    ngx_http_variable_value_t  *vv;

    if ((vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t))) == NULL) 
        return NGX_ERROR;

    ctx->unicode_path = 0;

#ifdef NGX_ZIP_HAVE_ICONV
    iconv_t *iconv_cd = NULL;

    if (ngx_http_upstream_header_variable(r, vv, (uintptr_t)(&ngx_http_zip_header_charset_name)) == NGX_OK 
            && !vv->not_found && ngx_strncmp(vv->data, "utf8", sizeof("utf8") - 1) != 0) {
        char encoding[ICONV_CSNMAXLEN];
        snprintf(encoding, sizeof(encoding), "%s//TRANSLIT//IGNORE", vv->data);

        iconv_cd = iconv_open((const char *)encoding, "utf-8");
        if (iconv_cd == (iconv_t)(-1)) {
            ngx_log_error(NGX_LOG_WARN, r->connection->log, errno,
                    "mod_zip: iconv_open('%s', 'utf-8') failed",
                    vv->data);
            iconv_cd = NULL;
        }
    }

    if (iconv_cd) {
        ctx->unicode_path = 1;
    }
#endif

    // pieces: for each file: header, data, footer (if needed) -> 2 or 3 per file
    // plus file footer (CD + [zip64 end + zip64 locator +] end of cd) in one chunk
    ctx->pieces_n = ctx->files.nelts * (2 + (!!ctx->missing_crc32)) + 1;

    if ((ctx->pieces = ngx_palloc(r->pool, sizeof(ngx_http_zip_piece_t) * ctx->pieces_n)) == NULL) 
        return NGX_ERROR;
    
    ctx->cd_size = 0;
    for (piece_i = i = 0; i < ctx->files.nelts; i++) {
        file = &((ngx_http_zip_file_t *)ctx->files.elts)[i];
        file->offset = offset;

#ifdef NGX_ZIP_HAVE_ICONV
        if (ctx->unicode_path) {
            size_t inlen = file->filename.len, outlen, outleft;
            u_char *p, *in;

            //inbuf
            file->filename_utf8.data = ngx_pnalloc(r->pool, file->filename.len + 1);
            ngx_memcpy(file->filename_utf8.data, file->filename.data, file->filename.len);
            file->filename_utf8.len = file->filename.len;
            file->filename_utf8.data[file->filename.len] = '\0';

            //outbuf
            outlen = outleft = inlen * sizeof(int) + 15;
            file->filename.data = ngx_pnalloc(r->pool, outlen + 1);

            in = file->filename_utf8.data;
            p = file->filename.data;

            //reset state
            iconv(iconv_cd, NULL, NULL, NULL, NULL);

            //convert the string
            iconv(iconv_cd, (char **)&in, &inlen, (char **)&p, &outleft);
	    //XXX if (res == (size_t)-1) { ? }
        
            file->filename.len = outlen - outleft;

            file->filename_utf8_crc32 = ngx_crc32_long(file->filename_utf8.data, file->filename_utf8.len);
        }
#endif

        if(offset >= (off_t) NGX_MAX_UINT32_VALUE)
            ctx->zip64_used = file->need_zip64_offset = 1;
        if(file->size >= (off_t) NGX_MAX_UINT32_VALUE) 
            ctx->zip64_used = file->need_zip64 = 1;

        ctx->cd_size += sizeof(ngx_zip_central_directory_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_central_t) 
            + (file->need_zip64_offset ? 
                    (file->need_zip64 ? sizeof(ngx_zip_extra_field_zip64_sizes_offset_t) : sizeof(ngx_zip_extra_field_zip64_offset_only_t)) :
                    (file->need_zip64 ? sizeof(ngx_zip_extra_field_zip64_sizes_only_t) : 0) +
                    (ctx->unicode_path ? (sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len): 0)
              );

        header_piece = &ctx->pieces[piece_i++];
        header_piece->type = zip_header_piece;
        header_piece->file = file;
        header_piece->range.start = offset;
        header_piece->range.end = offset += sizeof(ngx_zip_local_file_header_t)
            + file->filename.len + sizeof(ngx_zip_extra_field_local_t) + (file->need_zip64? sizeof(ngx_zip_extra_field_zip64_sizes_only_t):0)
            + (ctx->unicode_path ? (sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len): 0);

        file_piece = &ctx->pieces[piece_i++];
        file_piece->type = zip_file_piece;
        file_piece->file = file;
        file_piece->range.start = offset;
        file_piece->range.end = offset += file->size; //!note: (sizeless chunks): we need file size here / or mark it and modify ranges after

        if (file->missing_crc32) { // if incomplete header -> add footer with that info to file
            trailer_piece = &ctx->pieces[piece_i++];
            trailer_piece->type = zip_trailer_piece;
            trailer_piece->file = file;
            trailer_piece->range.start = offset;
            trailer_piece->range.end = offset += file->need_zip64? sizeof(ngx_zip_data_descriptor_zip64_t) : sizeof(ngx_zip_data_descriptor_t);
            //!!TODO: if we want Ranges support - here we know it is impossible for this set
            //? check conf/some state and abort?
        }
    }

#ifdef NGX_ZIP_HAVE_ICONV
    if (ctx->unicode_path) {
        iconv_close(iconv_cd);
    }
#endif

    ctx->zip64_used |= offset >= (off_t) NGX_MAX_UINT32_VALUE || ctx->files.nelts >= NGX_MAX_UINT16_VALUE;

    ctx->cd_size += sizeof(ngx_zip_end_of_central_directory_record_t);
    if (ctx->zip64_used)
        ctx->cd_size += sizeof(ngx_zip_zip64_end_of_central_directory_record_t) + sizeof(ngx_zip_zip64_end_of_central_directory_locator_t);


    cd_piece = &ctx->pieces[piece_i++];
    cd_piece->type = zip_central_directory_piece;
    cd_piece->range.start = offset;
    cd_piece->range.end = offset += ctx->cd_size;

    ctx->pieces_n = piece_i; //!! nasty hack (truncating allocated array without reallocation)

    ctx->archive_size = offset;

    return NGX_OK;
}