春哥,
fastdfs-nginx代码:https://github.com/happyfish100/fastdfs-nginx-module
fastdfs插件的流程:先查找本地文件,不存在则走反向代理。反向代理pc浏览器,安卓浏览器的range分配请求处理都正常,唯一是iphone浏览器请求不正常,无法观看。
后改成走storage插件下载数据再返回,发现pc浏览器返回正常,安卓浏览器不能正常观看,iphone浏览器播放卡顿。
春哥,能帮我看看我的文件哪里有问题么?
从日志里,2017/05/08 16:13:13 [alert] 23445#0: *27 header already sent, client: 122.13.132.180, server: test_dl.XXXX.com, request: "GET /group1/M00/00/84/3QVvm1kPLPuEfQ3bAAAAAF6v26w849.mp4 HTTP/1.1", host: "test_dl.XXXX.com:82"
在用安卓浏览器打开mp4文件,后台日志里有
[2017-05-08 16:13:13] ERROR - file: /home/ddd/fastdfs-nginx-module-master/src/common.c, line: 1271, storage_download_file_to_buff2 file_info_storage.file_size 23648845 file_size 23648845 download_bytes 0 return code: 0, pContext->if_range 0 elapse 232 pResponse->content_range file id: group1/M00/00/84/3QVvm1kPLPuEfQ3bAAAAAF6v26w849.mp4
2017/05/08 16:13:13 [alert] 23445#0: *27 header already sent, client: 122.13.132.180, server: test_dl.XXXX.com, request: "GET /group1/M00/00/84/3QVvm1kPLPuEfQ3bAAAAAF6v26w849.mp4 HTTP/1.1", host: "test_dl.XXXX.com:82"
已经发送数据给客户端,但是客户端没收到?
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#include <unistd.h>
#include "fdfs_define.h"
#include "logger.h"
#include "shared_func.h"
#include "fdfs_global.h"
#include "sockopt.h"
#include "http_func.h"
#include "fdfs_http_shared.h"
#include "fdfs_client.h"
#include "local_ip_func.h"
#include "fdfs_shared_func.h"
#include "trunk_shared.h"
#include "common.h"
#define FDFS_MOD_REPONSE_MODE_PROXY 'P'
#define FDFS_MOD_REPONSE_MODE_REDIRECT 'R'
static char flv_header[] = "FLV\x1\x1\0\0\0\x9\0\0\0\x9";
typedef struct tagGroupStorePaths {
char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
int group_name_len;
int storage_server_port;
FDFSStorePaths store_paths;
} GroupStorePaths;
static int storage_server_port = FDFS_STORAGE_SERVER_DEF_PORT;
static int my_group_name_len = 0;
static int group_count = 0; //for multi groups
static bool url_have_group_name = false;
static bool use_storage_id = false;
static bool flv_support = false; //if support flv
static char flv_extension[FDFS_FILE_EXT_NAME_MAX_LEN + 1] = {0}; //flv extension name
static int flv_ext_len = 0; //flv extension length
static char my_group_name[FDFS_GROUP_NAME_MAX_LEN + 1] = {0};
static char response_mode = FDFS_MOD_REPONSE_MODE_PROXY;
static GroupStorePaths *group_store_paths = NULL; //for multi groups
static FDFSHTTPParams g_http_params;
static int storage_sync_file_max_delay = 24 * 3600;
//static int storage_sync_file_min_delay = 5 * 60;
static int fdfs_get_params_from_tracker();
static int fdfs_format_http_datetime(time_t t, char *buff, const int buff_size);
static int fdfs_strtoll(const char *s, int64_t *value)
{
char *end = NULL;
*value = strtoll(s, &end, 10);
if (end != NULL && *end != '\0')
{
return EINVAL;
}
return 0;
}
static int fdfs_load_groups_store_paths(IniContext *pItemContext)
{
char section_name[64];
char *pGroupName;
int bytes;
int result;
int i;
bytes = sizeof(GroupStorePaths) * group_count;
group_store_paths = (GroupStorePaths *)malloc(bytes);
if (group_store_paths == NULL)
{
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, bytes, errno, STRERROR(errno));
return errno != 0 ? errno : ENOMEM;
}
for (i=0; i<group_count; i++)
{
sprintf(section_name, "group%d", i + 1);
pGroupName = iniGetStrValue(section_name, "group_name", \
pItemContext);
if (pGroupName == NULL)
{
logError("file: "__FILE__", line: %d, " \
"section: %s, you must set parameter: " \
"group_name!", __LINE__, section_name);
return ENOENT;
}
group_store_paths[i].storage_server_port = iniGetIntValue( \
section_name, "storage_server_port", pItemContext, \
FDFS_STORAGE_SERVER_DEF_PORT);
group_store_paths[i].group_name_len = snprintf( \
group_store_paths[i].group_name, \
sizeof(group_store_paths[i].group_name), \
"%s", pGroupName);
if (group_store_paths[i].group_name_len == 0)
{
logError("file: "__FILE__", line: %d, " \
"section: %s, parameter: group_name " \
"can't be empty!", __LINE__, section_name);
return EINVAL;
}
group_store_paths[i].store_paths.paths = \
storage_load_paths_from_conf_file_ex(pItemContext, \
section_name, false, &group_store_paths[i].store_paths.count, \
&result);
if (result != 0)
{
return result;
}
}
return 0;
}
int fdfs_mod_init()
{
IniContext iniContext;
int result;
int len;
int i;
char *pLogFilename;
char *pReponseMode;
char *pIfAliasPrefix;
char buff[2 * 1024];
bool load_fdfs_parameters_from_tracker = false;
log_init();
trunk_shared_init();
if ((result=iniLoadFromFile(FDFS_MOD_CONF_FILENAME, &iniContext)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"load conf file \"%s\" fail, ret code: %d", \
__LINE__, FDFS_MOD_CONF_FILENAME, result);
return result;
}
do
{
group_count = iniGetIntValue(NULL, "group_count", &iniContext, 0);
if (group_count < 0)
{
logError("file: "__FILE__", line: %d, " \
"conf file: %s, group_count: %d is invalid!", \
__LINE__, FDFS_MOD_CONF_FILENAME, group_count);
return EINVAL;
}
url_have_group_name = iniGetBoolValue(NULL, "url_have_group_name", \
&iniContext, false);
if (group_count > 0)
{
if (!url_have_group_name)
{
logError("file: "__FILE__", line: %d, " \
"config file: %s, you must set " \
"url_have_group_name to true to " \
"support multi-group!", \
__LINE__, FDFS_MOD_CONF_FILENAME);
result = ENOENT;
break;
}
if ((result=fdfs_load_groups_store_paths(&iniContext)) != 0)
{
break;
}
}
else
{
char *pGroupName;
pGroupName = iniGetStrValue(NULL, "group_name", &iniContext);
if (pGroupName == NULL)
{
logError("file: "__FILE__", line: %d, " \
"config file: %s, you must set parameter: " \
"group_name!", __LINE__, FDFS_MOD_CONF_FILENAME);
result = ENOENT;
break;
}
my_group_name_len = snprintf(my_group_name, \
sizeof(my_group_name), "%s", pGroupName);
if (my_group_name_len == 0)
{
logError("file: "__FILE__", line: %d, " \
"config file: %s, parameter: group_name " \
"can't be empty!", __LINE__, \
FDFS_MOD_CONF_FILENAME);
result = EINVAL;
break;
}
if ((result=storage_load_paths_from_conf_file(&iniContext)) != 0)
{
break;
}
}
g_fdfs_connect_timeout = iniGetIntValue(NULL, "connect_timeout", \
&iniContext, DEFAULT_CONNECT_TIMEOUT);
if (g_fdfs_connect_timeout <= 0)
{
g_fdfs_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
}
g_fdfs_network_timeout = iniGetIntValue(NULL, "network_timeout", \
&iniContext, DEFAULT_NETWORK_TIMEOUT);
if (g_fdfs_network_timeout <= 0)
{
g_fdfs_network_timeout = DEFAULT_NETWORK_TIMEOUT;
}
load_log_level(&iniContext);
pLogFilename = iniGetStrValue(NULL, "log_filename", &iniContext);
if (pLogFilename != NULL && *pLogFilename != '\0')
{
if ((result=log_set_filename(pLogFilename)) != 0)
{
break;
}
}
storage_server_port = iniGetIntValue(NULL, "storage_server_port", \
&iniContext, FDFS_STORAGE_SERVER_DEF_PORT);
if ((result=fdfs_http_params_load(&iniContext, FDFS_MOD_CONF_FILENAME, \
&g_http_params)) != 0)
{
break;
}
pReponseMode = iniGetStrValue(NULL, "response_mode", &iniContext);
if (pReponseMode != NULL)
{
if (strcmp(pReponseMode, "redirect") == 0)
{
response_mode = FDFS_MOD_REPONSE_MODE_REDIRECT;
}
}
pIfAliasPrefix = iniGetStrValue (NULL, "if_alias_prefix", &iniContext);
if (pIfAliasPrefix == NULL)
{
*g_if_alias_prefix = '\0';
}
else
{
snprintf(g_if_alias_prefix, sizeof(g_if_alias_prefix),
"%s", pIfAliasPrefix);
}
load_fdfs_parameters_from_tracker = iniGetBoolValue(NULL, \
"load_fdfs_parameters_from_tracker", \
&iniContext, false);
if (load_fdfs_parameters_from_tracker)
{
result = fdfs_load_tracker_group_ex(&g_tracker_group, \
FDFS_MOD_CONF_FILENAME, &iniContext);
}
else
{
storage_sync_file_max_delay = iniGetIntValue(NULL, \
"storage_sync_file_max_delay", \
&iniContext, 24 * 3600);
use_storage_id = iniGetBoolValue(NULL, "use_storage_id", \
&iniContext, false);
if (use_storage_id)
{
result = fdfs_load_storage_ids_from_file( \
FDFS_MOD_CONF_FILENAME, &iniContext);
}
}
} while (false);
flv_support = iniGetBoolValue(NULL, "flv_support", \
&iniContext, false);
if (flv_support)
{
char *flvExtension;
flvExtension = iniGetStrValue (NULL, "flv_extension", \
&iniContext);
if (flvExtension == NULL)
{
flv_ext_len = sprintf(flv_extension, "flv");
}
else
{
flv_ext_len = snprintf(flv_extension, \
sizeof(flv_extension), "%s", flvExtension);
}
}
iniFreeContext(&iniContext);
if (result != 0)
{
return result;
}
load_local_host_ip_addrs();
if (load_fdfs_parameters_from_tracker)
{
fdfs_get_params_from_tracker();
}
if (group_count > 0)
{
len = sprintf(buff, "group_count=%d, ", group_count);
}
else
{
len = sprintf(buff, "group_name=%s, storage_server_port=%d, " \
"path_count=%d, ", my_group_name, \
storage_server_port, g_fdfs_store_paths.count);
for (i=0; i<g_fdfs_store_paths.count; i++)
{
len += snprintf(buff + len, sizeof(buff) - len, \
"store_path%d=%s, ", i, \
g_fdfs_store_paths.paths[i]);
}
}
logInfo("fastdfs apache / nginx module v1.15, " \
"response_mode=%s, " \
"base_path=%s, " \
"url_have_group_name=%d, " \
"%s" \
"connect_timeout=%d, "\
"network_timeout=%d, "\
"tracker_server_count=%d, " \
"if_alias_prefix=%s, " \
"local_host_ip_count=%d, " \
"anti_steal_token=%d, " \
"token_ttl=%ds, " \
"anti_steal_secret_key length=%d, " \
"token_check_fail content_type=%s, " \
"token_check_fail buff length=%d, " \
"load_fdfs_parameters_from_tracker=%d, " \
"storage_sync_file_max_delay=%ds, " \
"use_storage_id=%d, storage server id count=%d, " \
"flv_support=%d, flv_extension=%s group_count=%d", \
response_mode == FDFS_MOD_REPONSE_MODE_PROXY ? \
"proxy" : "redirect", \
g_fdfs_base_path, url_have_group_name, buff, \
g_fdfs_connect_timeout, g_fdfs_network_timeout, \
g_tracker_group.server_count, \
g_if_alias_prefix, g_local_host_ip_count, \
g_http_params.anti_steal_token, \
g_http_params.token_ttl, \
g_http_params.anti_steal_secret_key.length, \
g_http_params.token_check_fail_content_type, \
g_http_params.token_check_fail_buff.length, \
load_fdfs_parameters_from_tracker, \
storage_sync_file_max_delay, use_storage_id, \
g_storage_id_count, flv_support, flv_extension,group_count);
if (group_count > 0)
{
int k;
for (k=0; k<group_count; k++)
{
len = 0;
*buff = '\0';
for (i=0; i<group_store_paths[k].store_paths.count; i++)
{
len += snprintf(buff + len, sizeof(buff) - len, \
", store_path%d=%s", i, \
group_store_paths[k].store_paths.paths[i]);
}
logInfo("group %d. group_name=%s, " \
"storage_server_port=%d, path_count=%d%s", \
k + 1, group_store_paths[k].group_name, \
storage_server_port, group_store_paths[k]. \
store_paths.count, buff);
}
}
//print_local_host_ip_addrs();
return 0;
}
#define OUTPUT_HEADERS(pContext, pResponse, http_status) \
pResponse->status = http_status; \
pContext->output_headers(pContext->arg, pResponse);
/*
static void fdfs_format_range(const struct fdfs_http_range *range, \
struct fdfs_http_response *pResponse)
{
if (range->start < 0)
{
pResponse->range_len = sprintf(pResponse->range, \
"bytes=%"PRId64, range->start);
}
else if (range->end == 0)
{
pResponse->range_len = sprintf(pResponse->range, \
"bytes=%"PRId64"-", range->start);
}
else
{
pResponse->range_len = sprintf(pResponse->range, \
"bytes=%"PRId64"-%"PRId64, \
range->start, range->end);
}
}
*/
static void fdfs_format_content_range(const struct fdfs_http_range *range, \
const int64_t file_size, struct fdfs_http_response *pResponse)
{
pResponse->content_range_len = sprintf(pResponse->content_range, \
"bytes %"PRId64"-%"PRId64 \
"/%"PRId64, range->start, range->end, file_size);
}
static int fdfs_check_and_format_range(struct fdfs_http_range *range,
const int64_t file_size)
{
if (range->start < 0)
{
int64_t start;
start = range->start + file_size;
if (start < 0)
{
logWarning("file: "__FILE__", line: %d, " \
"invalid range value: %"PRId64", set to 0", \
__LINE__, range->start);
start = 0;
}
range->start = start;
}
else if (range->start >= file_size)
{
logError("file: "__FILE__", line: %d, " \
"invalid range start value: %"PRId64 \
", exceeds file size: %"PRId64, \
__LINE__, range->start, file_size);
return EINVAL;
}
if (range->end == 0)
{
range->end = file_size - 1;
}
else if (range->end >= file_size)
{
logWarning("file: "__FILE__", line: %d, " \
"invalid range end value: %"PRId64 \
", exceeds file size: %"PRId64, \
__LINE__, range->end, file_size);
range->end = file_size - 1;
}
if (range->start > range->end)
{
logError("file: "__FILE__", line: %d, " \
"invalid range value, start: %"PRId64 \
", exceeds end: %"PRId64, \
__LINE__, range->start, range->end);
return EINVAL;
}
return 0;
}
/*
static int fdfs_download_callback(void *arg, const int64_t file_size, \
const char *data, const int current_size)
{
struct fdfs_download_callback_args *pCallbackArgs;
pCallbackArgs = (struct fdfs_download_callback_args *)arg;
if (!pCallbackArgs->pResponse->header_outputed)
{
pCallbackArgs->pResponse->content_length = file_size;
OUTPUT_HEADERS(pCallbackArgs->pContext, \
pCallbackArgs->pResponse, pCallbackArgs->pContext->if_range?HTTP_PARTIAL_CONTENT:HTTP_OK)
}
pCallbackArgs->sent_bytes += current_size;
return pCallbackArgs->pContext->send_reply_chunk( \
pCallbackArgs->pContext->arg, \
(pCallbackArgs->sent_bytes == file_size) ? 1 : 0, \
data, current_size);
}
*/
#define FDFS_SET_LAST_MODIFIED(response, pContext, mtime) \
do { \
response.last_modified = mtime; \
fdfs_format_http_datetime(response.last_modified, \
response.last_modified_buff, \
sizeof(response.last_modified_buff)); \
if (*pContext->if_modified_since != '\0') \
{ \
if (strcmp(response.last_modified_buff, \
pContext->if_modified_since) == 0) \
{ \
OUTPUT_HEADERS(pContext, (&response), HTTP_NOTMODIFIED)\
logError("file: "__FILE__", line: %d HTTP_NOTMODIFIED",__LINE__);\
return HTTP_NOTMODIFIED; \
} \
} \
\
\
logError("file: "__FILE__", line: %d, last_modified: %s, if_modified_since: %s, strcmp=%d", \
__LINE__,response.last_modified_buff, \
pContext->if_modified_since, \
strcmp(response.last_modified_buff, \
pContext->if_modified_since)); \
\
} while (0)
int fdfs_http_request_handler(struct fdfs_http_context *pContext)
{
#define HTTPD_MAX_PARAMS 32
char *file_id_without_group;
char *url;
char file_id[128];
char uri[512];
int url_len;
int uri_len;
int flv_header_len;
int param_count;
int ext_len;
KeyValuePair params[HTTPD_MAX_PARAMS];
char *p;
char *filename;
const char *ext_name;
FDFSStorePaths *pStorePaths;
char true_filename[128];
char full_filename[MAX_PATH_SIZE + 64];
//char content_type[64];
char file_trunk_buff[FDFS_OUTPUT_CHUNK_SIZE];
struct stat file_stat;
int64_t file_offset;
int64_t file_size;
int64_t download_bytes;
off_t remain_bytes;
int read_bytes;
int filename_len;
int full_filename_len;
int store_path_index;
int fd;
int result;
int http_status;
int the_storage_port;
struct fdfs_http_response response;
FDFSFileInfo file_info;
//bool bFileExists;
bool bSameGroup; //if in my group
bool bTrunkFile;
FDFSTrunkFullInfo trunkInfo;
memset(&response, 0, sizeof(response));
response.status = HTTP_OK;
//logInfo("url=%s", pContext->url);
//int64_t startTime = time(NULL);
struct timeval stv;
gettimeofday(&stv, NULL);
int64_t startTime = (int64_t)stv.tv_sec * 1000 + (int64_t)stv.tv_usec/1000;
url_len = strlen(pContext->url);
if (url_len < 16)
{
logError("file: "__FILE__", line: %d, " \
"url length: %d < 16", __LINE__, url_len);
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
if (strncasecmp(pContext->url, "http://", 7) == 0)
{
p = strchr(pContext->url + 7, '/');
if (p == NULL)
{
logError("file: "__FILE__", line: %d, " \
"invalid url: %s", __LINE__, pContext->url);
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
uri_len = url_len - (p - pContext->url);
url = p;
}
else
{
uri_len = url_len;
url = pContext->url;
}
if (uri_len + 1 >= (int)sizeof(uri))
{
logError("file: "__FILE__", line: %d, " \
"uri length: %d is too long, >= %d", __LINE__, \
uri_len, (int)sizeof(uri));
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
if (*url != '/')
{
*uri = '/';
memcpy(uri+1, url, uri_len+1);
uri_len++;
}
else
{
memcpy(uri, url, uri_len+1);
}
the_storage_port = storage_server_port;
param_count = http_parse_query(uri, params, HTTPD_MAX_PARAMS);
if (url_have_group_name)
{
int group_name_len;
snprintf(file_id, sizeof(file_id), "%s", uri + 1);
file_id_without_group = strchr(file_id, '/');
if (file_id_without_group == NULL)
{
logError("file: "__FILE__", line: %d, " \
"no group name in url, uri: %s", __LINE__, uri);
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
pStorePaths = &g_fdfs_store_paths;
group_name_len = file_id_without_group - file_id;
if (group_count == 0)
{
bSameGroup = (group_name_len == my_group_name_len) && \
(memcmp(file_id, my_group_name, \
group_name_len) == 0);
}
else
{
int i;
bSameGroup = false;
for (i=0; i<group_count; i++)
{
if (group_store_paths[i].group_name_len == \
group_name_len && memcmp(file_id, \
group_store_paths[i].group_name, \
group_name_len) == 0)
{
the_storage_port = group_store_paths[i]. \
storage_server_port;
bSameGroup = true;
pStorePaths = &group_store_paths[i].store_paths;
break;
}
}
}
file_id_without_group++; //skip /
}
else
{
pStorePaths = &g_fdfs_store_paths;
bSameGroup = true;
file_id_without_group = uri + 1; //skip /
snprintf(file_id, sizeof(file_id), "%s/%s", \
my_group_name, file_id_without_group);
}
if (strlen(file_id_without_group) < 22)
{
logError("file: "__FILE__", line: %d, " \
"file id is too short, length: %d < 22, " \
"uri: %s", __LINE__, \
(int)strlen(file_id_without_group), uri);
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
if (g_http_params.anti_steal_token)
{
char *token;
char *ts;
int timestamp;
token = fdfs_http_get_parameter("token", params, param_count);
ts = fdfs_http_get_parameter("ts", params, param_count);
if (token == NULL || ts == NULL)
{
logError("file: "__FILE__", line: %d, " \
"expect parameter token or ts in url, " \
"uri: %s", __LINE__, uri);
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
timestamp = atoi(ts);
if ((result=fdfs_http_check_token( \
&g_http_params.anti_steal_secret_key, \
file_id_without_group, timestamp, token, \
g_http_params.token_ttl)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"check token fail, uri: %s, " \
"errno: %d, error info: %s", \
__LINE__, uri, result, STRERROR(result));
if (*(g_http_params.token_check_fail_content_type))
{
response.content_length = g_http_params. \
token_check_fail_buff.length;
response.content_type = g_http_params. \
token_check_fail_content_type;
OUTPUT_HEADERS(pContext, (&response), HTTP_OK)
pContext->send_reply_chunk(pContext->arg, 1, \
g_http_params.token_check_fail_buff.buff,
g_http_params.token_check_fail_buff.length);
return HTTP_OK;
}
else
{
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
}
}
filename = file_id_without_group;
filename_len = strlen(filename);
if (storage_split_filename_no_check(filename, \
&filename_len, true_filename, &store_path_index) != 0)
{
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
if (bSameGroup)
{
if (store_path_index < 0 || \
store_path_index >= pStorePaths->count)
{
logError("file: "__FILE__", line: %d, " \
"filename: %s is invalid, " \
"invalid store path index: %d, " \
"which < 0 or >= %d", __LINE__, filename, \
store_path_index, pStorePaths->count);
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
}
if (fdfs_check_data_filename(true_filename, filename_len) != 0)
{
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
if ((result=fdfs_get_file_info_ex1(file_id, false, &file_info)) != 0)
{
if (result == ENOENT)
{
http_status = HTTP_NOTFOUND;
}
else if (result == EINVAL)
{
http_status = HTTP_BADREQUEST;
}
else
{
http_status = HTTP_INTERNAL_SERVER_ERROR;
}
OUTPUT_HEADERS(pContext, (&response), http_status)
return http_status;
}
fd = -1;
memset(&file_stat, 0, sizeof(file_stat));
if (bSameGroup)
{
FDFSTrunkHeader trunkHeader;
if ((result=trunk_file_stat_ex1(pStorePaths, store_path_index, \
true_filename, filename_len, &file_stat, \
&trunkInfo, &trunkHeader, &fd)) != 0)
{
//bFileExists = false;
}
else
{
//bFileExists = true;
}
}
else
{
//bFileExists = false;
memset(&trunkInfo, 0, sizeof(trunkInfo));
}
response.attachment_filename = fdfs_http_get_parameter("filename", \
params, param_count);
ConnectionInfo storage_server;
strcpy(storage_server.ip_addr, file_info.source_ip_addr);
storage_server.port = the_storage_port;
storage_server.sock = -1;
FDFSFileInfo file_info_storage;
result = storage_query_file_info_ex1(NULL,\
&storage_server, file_id, \
&file_info_storage, false);
if (result != 0)
{
OUTPUT_HEADERS(pContext, (&response), HTTP_INTERNAL_SERVER_ERROR)
return HTTP_INTERNAL_SERVER_ERROR;
}
if (file_info_storage.file_size >= 0) //normal file
{
FDFS_SET_LAST_MODIFIED(response, pContext, \
file_info_storage.create_timestamp);
}
bool isCanReadLocal = file_stat.st_size == file_info_storage.file_size;
logError("file: "__FILE__", line: %d, " \
"isCanReadLocal %d file_stat.st_size %u file_info_storage.file_size %u " \
"file id: %s", __LINE__, isCanReadLocal,file_stat.st_size,file_info_storage.file_size,file_id);
if (isCanReadLocal)
{
if (file_info.file_size < 0) //slave or appender file
{
FDFS_SET_LAST_MODIFIED(response, pContext, \
file_stat.st_mtime);
}
}
else
{
/*
char *redirect;
logError("file: "__FILE__", line: %d, source id: %d",__LINE__, file_info.source_id);
//logInfo("source ip addr: %s", file_info.source_ip_addr);
//logInfo("create_timestamp: %d", file_info.create_timestamp);
if (bSameGroup && (is_local_host_ip(file_info.source_ip_addr) \
|| (file_info.create_timestamp > 0 && (time(NULL) - \
file_info.create_timestamp > storage_sync_file_max_delay))))
{
if (IS_TRUNK_FILE_BY_ID(trunkInfo))
{
if (result == ENOENT)
{
logError("file: "__FILE__", line: %d, "\
"logic file: %s not exist", \
__LINE__, filename);
}
else
{
logError("file: "__FILE__", line: %d, "\
"stat logic file: %s fail, " \
"errno: %d, error info: %s", \
__LINE__, filename, result, \
STRERROR(result));
}
}
else
{
snprintf(full_filename, \
sizeof(full_filename), "%s/data/%s", \
pStorePaths->paths[store_path_index], \
true_filename);
if (result == ENOENT)
{
logError("file: "__FILE__", line: %d, "\
"file: %s not exist", \
__LINE__, full_filename);
}
else
{
logError("file: "__FILE__", line: %d, "\
"stat file: %s fail, " \
"errno: %d, error info: %s", \
__LINE__, full_filename, \
result, STRERROR(result));
}
}
OUTPUT_HEADERS(pContext, (&response), HTTP_NOTFOUND)
return HTTP_NOTFOUND;
}
redirect = fdfs_http_get_parameter("redirect", \
params, param_count);
if (redirect != NULL)
{
logError("file: "__FILE__", line: %d, " \
"redirect again, url: %s", \
__LINE__, url);
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
if (*(file_info.source_ip_addr) == '\0')
{
logError("file: "__FILE__", line: %d, " \
"can't get ip address of source storage " \
"id: %d, url: %s", __LINE__, \
file_info.source_id, url);
OUTPUT_HEADERS(pContext, (&response), \
HTTP_INTERNAL_SERVER_ERROR)
return HTTP_INTERNAL_SERVER_ERROR;
}
//logError("source id: %d response_mode %s", file_info.source_id,response_mode);
if (response_mode == FDFS_MOD_REPONSE_MODE_REDIRECT)
{
char *path_split_str;
char port_part[16];
char param_split_char;
if (pContext->server_port == 80)
{
*port_part = '\0';
}
else
{
sprintf(port_part, ":%d", pContext->server_port);
}
if (param_count == 0)
{
param_split_char = '?';
}
else
{
param_split_char = '&';
}
if (*url != '/')
{
path_split_str = "/";
}
else
{
path_split_str = "";
}
response.redirect_url_len = snprintf( \
response.redirect_url, \
sizeof(response.redirect_url), \
"http://%s%s%s%s%c%s", \
file_info.source_ip_addr, port_part, \
path_split_str, url, \
param_split_char, "redirect=1");
logError("file: "__FILE__", line: %d, " \
"redirect to %s", \
__LINE__, response.redirect_url);
if (pContext->if_range)
{
fdfs_format_range(&(pContext->range), &response);
}
OUTPUT_HEADERS(pContext, (&response), HTTP_MOVETEMP)
return HTTP_MOVETEMP;
}
else if (pContext->proxy_handler != NULL)
{
logError("file: "__FILE__", line: %d, " \
"proxy_handler pContext->if_range %d file_info.source_ip_addr %s", \
__LINE__, pContext->if_range,file_info.source_ip_addr);
return pContext->proxy_handler(pContext->arg, \
file_info.source_ip_addr);
}
*/
}
ext_name = fdfs_http_get_file_extension(true_filename, \
filename_len, &ext_len);
if (isCanReadLocal)
{
file_size = file_stat.st_size;
}
else
{
bool if_get_file_info;
if_get_file_info = pContext->header_only || \
(pContext->if_range && file_info.file_size < 0);
if (if_get_file_info)
{
if ((result=fdfs_get_file_info_ex1(file_id, true, \
&file_info)) != 0)
{
if (result == ENOENT)
{
http_status = HTTP_NOTFOUND;
}
else
{
http_status = HTTP_INTERNAL_SERVER_ERROR;
}
OUTPUT_HEADERS(pContext, (&response), http_status)
return http_status;
}
}
//appender 后不准 -1
file_size = file_info.file_size;
}
flv_header_len = 0;
if (isCanReadLocal)
{
if ( pContext->if_range)
{
if (fdfs_check_and_format_range(&(pContext->range), \
file_size) != 0)
{
if (fd >= 0)
{
close(fd);
}
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
download_bytes = (pContext->range.end - pContext->range.start) + 1;
fdfs_format_content_range(&(pContext->range), \
file_size, &response);
}
else
{
download_bytes = file_size > 0 ? file_size : 0;
//flv support
if (flv_support && (flv_ext_len == ext_len && \
memcmp(ext_name, flv_extension, ext_len) == 0))
{
char *pStart;
pStart = fdfs_http_get_parameter("start", \
params, param_count);
if (pStart != NULL)
{
int64_t start;
if (fdfs_strtoll(pStart, &start) == 0)
{
char *pEnd;
pContext->range.start = start;
pContext->range.end = 0;
pEnd = fdfs_http_get_parameter("end", \
params, param_count);
if (pEnd != NULL)
{
int64_t end;
if (fdfs_strtoll(pEnd, &end) == 0)
{
pContext->range.end = end - 1;
}
}
if (fdfs_check_and_format_range(&(pContext->range), \
file_size) != 0)
{
if (fd >= 0)
{
close(fd);
}
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
download_bytes = (pContext->range.end - pContext->range.start) + 1;
if (start > 0)
{
flv_header_len = sizeof(flv_header) - 1;
}
}
}
}
}
}
else
{
download_bytes = 0;
//flv support
if (flv_support && (flv_ext_len == ext_len && \
memcmp(ext_name, flv_extension, ext_len) == 0))
{
char *pStart;
pStart = fdfs_http_get_parameter("start", \
params, param_count);
if (pStart != NULL)
{
int64_t start;
if (fdfs_strtoll(pStart, &start) == 0)
{
char *pEnd;
pContext->range.start = start;
pContext->range.end = 0;
pEnd = fdfs_http_get_parameter("end", \
params, param_count);
if (pEnd != NULL)
{
int64_t end;
if (fdfs_strtoll(pEnd, &end) == 0)
{
pContext->range.end = end - 1;
}
}
if (fdfs_check_and_format_range(&(pContext->range), \
file_size) != 0)
{
if (fd >= 0)
{
close(fd);
}
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
//download_bytes = (pContext->range.end - pContext->range.start) + 1;
if (start > 0)
{
flv_header_len = sizeof(flv_header) - 1;
}
}
}
}
}
if (pContext->header_only)
{
if (fd >= 0)
{
close(fd);
}
response.content_length = download_bytes + flv_header_len;
OUTPUT_HEADERS(pContext, (&response), pContext->if_range ? \
HTTP_PARTIAL_CONTENT : HTTP_OK )
return HTTP_OK;
}
if (!isCanReadLocal)
{
/*
struct fdfs_download_callback_args callback_args;
callback_args.pContext = pContext;
callback_args.pResponse = &response;
callback_args.sent_bytes = 0;
*/
int64_t file_size;
if (pContext->if_range)
{
if (fdfs_check_and_format_range(&(pContext->range),file_info_storage.file_size) != 0)
{
OUTPUT_HEADERS(pContext, (&response), HTTP_BADREQUEST)
return HTTP_BADREQUEST;
}
download_bytes = (pContext->range.end - pContext->range.start) + 1;
//构造如:Content-Range: bytes 65536-23648844/23648845
fdfs_format_content_range(&(pContext->range),file_info_storage.file_size, (&response));
}
else
{
//filesize不准确(文件名里的不准确不能作为文件大小的依据) 需从storage下载全部,
download_bytes = 0;
}
/*
result = storage_download_file_ex1(NULL, \
&storage_server, file_id, \
pContext->range.start, download_bytes, \
fdfs_download_callback, &callback_args, &file_size);
*/
char *fdfs_download_buf = NULL;
result = storage_download_file_to_buff2(NULL, \
&storage_server, file_id, \
pContext->range.start, download_bytes, \
&fdfs_download_buf, &file_size);
if (result == 0)
{
response.content_length = file_size;
OUTPUT_HEADERS(pContext, (&response), pContext->if_range?HTTP_PARTIAL_CONTENT:HTTP_OK)
result = pContext->send_reply_chunk1(pContext->arg, (unsigned char *)fdfs_download_buf, (size_t)file_size);
}
struct timeval stv;
gettimeofday(&stv, NULL);
int64_t endTime = (int64_t)stv.tv_sec * 1000 + (int64_t)stv.tv_usec/1000;
logError("file: "__FILE__", line: %d, " \
"storage_download_file_to_buff2 file_info_storage.file_size %u file_size %u download_bytes %u return code: %d, pContext->if_range %u elapse %u pResponse->content_range %s " \
"file id: %s", __LINE__, file_info_storage.file_size,file_size,download_bytes,result,pContext->if_range,endTime - startTime,response.content_range, file_id);
if (result == 0)
{
http_status = HTTP_OK;
}
if (result == ENOENT)
{
http_status = HTTP_NOTFOUND;
}
else
{
http_status = HTTP_INTERNAL_SERVER_ERROR;
}
//OUTPUT_HEADERS(pContext, (&response), http_status)
if (fdfs_download_buf) {
free(fdfs_download_buf);
fdfs_download_buf = NULL;
}
OUTPUT_HEADERS(pContext, (&response), http_status)
return http_status;
}
bTrunkFile = IS_TRUNK_FILE_BY_ID(trunkInfo);
if (bTrunkFile)
{
trunk_get_full_filename_ex(pStorePaths, &trunkInfo, \
full_filename, sizeof(full_filename));
full_filename_len = strlen(full_filename);
file_offset = TRUNK_FILE_START_OFFSET(trunkInfo) + \
pContext->range.start;
}
else
{
full_filename_len = snprintf(full_filename, \
sizeof(full_filename), "%s/data/%s", \
pStorePaths->paths[store_path_index], \
true_filename);
file_offset = pContext->range.start;
}
response.content_length = download_bytes + flv_header_len;
if (pContext->send_file != NULL && !bTrunkFile)
{
http_status = pContext->if_range ? \
HTTP_PARTIAL_CONTENT : HTTP_OK;
OUTPUT_HEADERS(pContext, (&response), http_status)
if (flv_header_len > 0)
{
if (pContext->send_reply_chunk(pContext->arg, \
false, flv_header, flv_header_len) != 0)
{
close(fd);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
return pContext->send_file(pContext->arg, full_filename, \
full_filename_len, file_offset, download_bytes);
}
if (fd < 0)
{
fd = open(full_filename, O_RDONLY);
if (fd < 0)
{
logError("file: "__FILE__", line: %d, " \
"open file %s fail, " \
"errno: %d, error info: %s", __LINE__, \
full_filename, errno, STRERROR(errno));
OUTPUT_HEADERS(pContext, (&response), \
HTTP_SERVUNAVAIL)
return HTTP_SERVUNAVAIL;
}
if (file_offset > 0 && lseek(fd, file_offset, SEEK_SET) < 0)
{
close(fd);
logError("file: "__FILE__", line: %d, " \
"lseek file: %s fail, " \
"errno: %d, error info: %s", \
__LINE__, full_filename, \
errno, STRERROR(errno));
OUTPUT_HEADERS(pContext, (&response), \
HTTP_INTERNAL_SERVER_ERROR)
return HTTP_INTERNAL_SERVER_ERROR;
}
}
else
{
if (pContext->range.start > 0 && \
lseek(fd, pContext->range.start, SEEK_CUR) < 0)
{
close(fd);
logError("file: "__FILE__", line: %d, " \
"lseek file: %s fail, " \
"errno: %d, error info: %s", \
__LINE__, full_filename, \
errno, STRERROR(errno));
OUTPUT_HEADERS(pContext, (&response), \
HTTP_INTERNAL_SERVER_ERROR)
return HTTP_INTERNAL_SERVER_ERROR;
}
}
logError("file: "__FILE__",line: %d, pContext->if_range: %d", __LINE__,pContext->if_range);
OUTPUT_HEADERS(pContext, (&response), pContext->if_range ? \
HTTP_PARTIAL_CONTENT : HTTP_OK)
if (flv_header_len > 0)
{
if (pContext->send_reply_chunk(pContext->arg, \
false, flv_header, flv_header_len) != 0)
{
close(fd);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
remain_bytes = download_bytes;
while (remain_bytes > 0)
{
read_bytes = remain_bytes <= FDFS_OUTPUT_CHUNK_SIZE ? \
remain_bytes : FDFS_OUTPUT_CHUNK_SIZE;
if (read(fd, file_trunk_buff, read_bytes) != read_bytes)
{
close(fd);
logError("file: "__FILE__", line: %d, " \
"read from file %s fail, " \
"errno: %d, error info: %s", __LINE__, \
full_filename, errno, STRERROR(errno));
return HTTP_INTERNAL_SERVER_ERROR;
}
remain_bytes -= read_bytes;
if (pContext->send_reply_chunk(pContext->arg, \
(remain_bytes == 0) ? 1: 0, file_trunk_buff, \
read_bytes) != 0)
{
close(fd);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
close(fd);
return HTTP_OK;
}
static int fdfs_get_params_from_tracker()
{
IniContext iniContext;
int result;
bool continue_flag;
continue_flag = false;
if ((result=fdfs_get_ini_context_from_tracker(&g_tracker_group, \
&iniContext, &continue_flag, false, NULL)) != 0)
{
return result;
}
storage_sync_file_max_delay = iniGetIntValue(NULL, \
"storage_sync_file_max_delay", \
&iniContext, 24 * 3600);
use_storage_id = iniGetBoolValue(NULL, "use_storage_id", \
&iniContext, false);
iniFreeContext(&iniContext);
if (use_storage_id)
{
result = fdfs_get_storage_ids_from_tracker_group( \
&g_tracker_group);
}
return result;
}
static int fdfs_format_http_datetime(time_t t, char *buff, const int buff_size)
{
struct tm tm;
struct tm *ptm;
*buff = '\0';
if ((ptm=gmtime_r(&t, &tm)) == NULL)
{
return errno != 0 ? errno : EFAULT;
}
strftime(buff, buff_size, "%a, %d %b %Y %H:%M:%S GMT", ptm);
return 0;
}
int fdfs_parse_range(const char *value, struct fdfs_http_range *range)
{
/*
range format:
bytes=500-999
bytes=-500
bytes=9500-
*/
#define RANGE_PREFIX_STR "bytes="
#define RANGE_PREFIX_LEN (int)(sizeof(RANGE_PREFIX_STR) - 1)
int len;
int result;
const char *p;
const char *pEndPos;
char buff[32];
len = strlen(value);
if (len <= RANGE_PREFIX_LEN + 1)
{
return EINVAL;
}
p = value + RANGE_PREFIX_LEN;
if (*p == '-')
{
if ((result=fdfs_strtoll(p, &(range->start))) != 0)
{
return result;
}
range->end = 0;
return 0;
}
pEndPos = strchr(p, '-');
if (pEndPos == NULL)
{
return EINVAL;
}
len = pEndPos - p;
if (len >= (int)sizeof(buff))
{
return EINVAL;
}
memcpy(buff, p, len);
*(buff + len) = '\0';
if ((result=fdfs_strtoll(buff, &(range->start))) != 0)
{
return result;
}
pEndPos++; //skip -
if (*pEndPos == '\0')
{
range->end = 0;
}
else
{
if ((result=fdfs_strtoll(pEndPos, &(range->end))) != 0)
{
return result;
}
}
return 0;
}
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#ifndef FDFS_MOD_COMMON_H
#define FDFS_MOD_COMMON_H
#include <time.h>
#include "tracker_types.h"
#ifndef HTTP_OK
#define HTTP_OK 200
#endif
#ifndef HTTP_NOCONTENT
#define HTTP_NOCONTENT 204
#endif
#ifndef HTTP_PARTIAL_CONTENT
#define HTTP_PARTIAL_CONTENT 206
#endif
#ifndef HTTP_MOVEPERM
#define HTTP_MOVEPERM 301
#endif
#ifndef HTTP_MOVETEMP
#define HTTP_MOVETEMP 302
#endif
#ifndef HTTP_NOTMODIFIED
#define HTTP_NOTMODIFIED 304
#endif
#ifndef HTTP_BADREQUEST
#define HTTP_BADREQUEST 400
#endif
#ifndef HTTP_NOTFOUND
#define HTTP_NOTFOUND 404
#endif
#ifndef HTTP_INTERNAL_SERVER_ERROR
#define HTTP_INTERNAL_SERVER_ERROR 500
#endif
#ifndef HTTP_SERVUNAVAIL
#define HTTP_SERVUNAVAIL 503
#endif
#ifndef FDFS_STORAGE_STORE_PATH_PREFIX_CHAR
#define FDFS_STORAGE_STORE_PATH_PREFIX_CHAR 'M'
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct fdfs_http_response;
typedef void (*FDFSOutputHeaders)(void *arg, struct fdfs_http_response *pResponse);
typedef int (*FDFSSendReplyChunk)(void *arg, const bool last_buff, \
const char *buff, const int size);
typedef int (*FDFSSendReplyChunk1)(void *arg, \
const unsigned char *buff, const size_t size);
typedef int (*FDFSSendFile)(void *arg, const char *filename, \
const int filename_len, const int64_t file_offset, \
const int64_t download_bytes);
typedef int (*FDFSProxyHandler)(void *arg, const char *dest_ip_addr);
struct fdfs_http_response {
int status; //HTTP status
time_t last_modified; //last modified time of the file
int redirect_url_len;
int range_len;
int content_range_len;
int64_t content_length;
char *content_type;
char *attachment_filename;
char redirect_url[256];
char content_disposition[128];
char range[64];
char content_range[64];
char last_modified_buff[32];
bool header_outputed; //if header output
};
struct fdfs_http_range {
int64_t start;
int64_t end;
};
struct fdfs_http_context {
int server_port;
bool header_only;
bool if_range;
struct fdfs_http_range range;
char if_modified_since[32];
char *url;
void *arg; //for callback
FDFSOutputHeaders output_headers;
FDFSSendFile send_file; //nginx send file
FDFSSendReplyChunk send_reply_chunk;
FDFSSendReplyChunk1 send_reply_chunk1;
FDFSProxyHandler proxy_handler; //nginx proxy handler
};
struct fdfs_download_callback_args {
struct fdfs_http_context *pContext;
struct fdfs_http_response *pResponse;
int64_t sent_bytes; //sent bytes
};
/**
* init function
* params:
* return: 0 success, !=0 fail, return the error code
*/
int fdfs_mod_init();
/**
* http request handler
* params:
* pContext the context
* return: http status code, HTTP_OK success, != HTTP_OK fail
*/
int fdfs_http_request_handler(struct fdfs_http_context *pContext);
/**
* format http datetime
* params:
* t the time
* buff the string buffer
* buff_size the buffer size
* return: 0 success, !=0 fail, return the error code
*/
//int fdfs_format_http_datetime(time_t t, char *buff, const int buff_size);
/**
* parse range parameter
* params:
* value the range value
* rang the range object, store start and end position
* return: 0 success, !=0 fail, return the error code
*/
int fdfs_parse_range(const char *value, struct fdfs_http_range *range);
#ifdef __cplusplus
}
#endif
#endif
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <sys/types.h>
#include <unistd.h>
#include "common.c"
typedef struct {
ngx_http_upstream_conf_t upstream;
ngx_uint_t headers_hash_max_size;
ngx_uint_t headers_hash_bucket_size;
} ngx_http_fastdfs_loc_conf_t;
static char *ngx_http_fastdfs_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_fastdfs_process_init(ngx_cycle_t *cycle);
static void ngx_http_fastdfs_process_exit(ngx_cycle_t *cycle);
static int ngx_http_fastdfs_proxy_handler(void *arg, const char *dest_ip_addr);
static ngx_int_t ngx_http_fastdfs_proxy_process_status_line(ngx_http_request_t *r);
static ngx_int_t ngx_http_fastdfs_proxy_process_header(ngx_http_request_t *r);
static void *ngx_http_fastdfs_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_fastdfs_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
typedef struct {
ngx_http_status_t status;
char dest_ip_addr[IP_ADDRESS_SIZE];
} ngx_http_fastdfs_proxy_ctx_t;
static char ngx_http_fastdfs_proxy_version[] = " HTTP/1.0"CRLF;
static ngx_str_t ngx_http_proxy_hide_headers[] = {
ngx_string("Date"),
ngx_string("Server"),
ngx_string("X-Pad"),
ngx_string("X-Accel-Expires"),
ngx_string("X-Accel-Redirect"),
ngx_string("X-Accel-Limit-Rate"),
ngx_string("X-Accel-Buffering"),
ngx_string("X-Accel-Charset"),
ngx_null_string
};
/* Commands */
static ngx_command_t ngx_http_fastdfs_commands[] = {
{ ngx_string("ngx_fastdfs_module"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_fastdfs_set,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_fastdfs_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_fastdfs_create_loc_conf, /* create location configration */
ngx_http_fastdfs_merge_loc_conf /* merge location configration */
};
/* hook */
ngx_module_t ngx_http_fastdfs_module = {
NGX_MODULE_V1,
&ngx_http_fastdfs_module_ctx, /* module context */
ngx_http_fastdfs_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
ngx_http_fastdfs_process_init, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
ngx_http_fastdfs_process_exit, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t fdfs_set_header(ngx_http_request_t *r, \
const char *key, const char *low_key, const int key_len, \
char *value, const int value_len)
{
ngx_table_elt_t *cc;
cc = ngx_list_push(&r->headers_out.headers);
if (cc == NULL)
{
return NGX_ERROR;
}
cc->hash = 1;
cc->key.len = key_len;
cc->key.data = (u_char *)key;
cc->lowcase_key = (u_char *)low_key;
cc->value.len = value_len;
cc->value.data = (u_char *)value;
return NGX_OK;
}
static ngx_int_t fdfs_set_content_disposition(ngx_http_request_t *r, \
struct fdfs_http_response *pResponse)
{
int value_len;
value_len = snprintf(pResponse->content_disposition, \
sizeof(pResponse->content_disposition), \
"attachment; filename=\"%s\"", pResponse->attachment_filename);
return fdfs_set_header(r, "Content-Disposition", "content-disposition",\
sizeof("Content-Disposition") - 1, \
pResponse->content_disposition, value_len);
}
static ngx_int_t fdfs_set_range(ngx_http_request_t *r, \
struct fdfs_http_response *pResponse)
{
return fdfs_set_header(r, "Range", "range", \
sizeof("Range") - 1, pResponse->range, pResponse->range_len);
}
static ngx_int_t fdfs_set_content_range(ngx_http_request_t *r, \
struct fdfs_http_response *pResponse)
{
return fdfs_set_header(r, "Content-Range", "content-range", \
sizeof("Content-Range") - 1, pResponse->content_range, \
pResponse->content_range_len);
}
static ngx_int_t fdfs_set_accept_ranges(ngx_http_request_t *r)
{
return fdfs_set_header(r, "Accept-Ranges", "accept-ranges", \
sizeof("Accept-Ranges") - 1, "bytes", sizeof("bytes") - 1);
}
static ngx_int_t fdfs_set_location(ngx_http_request_t *r, \
struct fdfs_http_response *pResponse)
{
ngx_table_elt_t *cc;
cc = r->headers_out.location;
if (cc == NULL)
{
cc = ngx_list_push(&r->headers_out.headers);
if (cc == NULL)
{
return NGX_ERROR;
}
cc->hash = 1;
cc->key.len = sizeof("Location") - 1;
cc->key.data = (u_char *)"Location";
cc->lowcase_key = (u_char *)"location";
}
cc->value.len = pResponse->redirect_url_len;
cc->value.data = (u_char *)pResponse->redirect_url;
return NGX_OK;
}
static void fdfs_output_headers(void *arg, struct fdfs_http_response *pResponse)
{
ngx_http_request_t *r;
ngx_int_t rc;
if (pResponse->header_outputed)
{
return;
}
r = (ngx_http_request_t *)arg;
if (pResponse->status != HTTP_OK \
&& pResponse->status != HTTP_PARTIAL_CONTENT)
{
if (pResponse->status == HTTP_MOVETEMP)
{
if (pResponse->range_len > 0)
{
fdfs_set_range(r, pResponse);
}
fdfs_set_location(r, pResponse);
}
else
{
return; //does not send http header for other status
}
}
else
{
if (pResponse->content_type != NULL)
{
r->headers_out.content_type.len = strlen(pResponse->content_type);
r->headers_out.content_type.data = (u_char *)pResponse->content_type;
}
r->headers_out.content_length_n = pResponse->content_length;
if (pResponse->attachment_filename != NULL)
{
fdfs_set_content_disposition(r, pResponse);
}
r->headers_out.last_modified_time = pResponse->last_modified;
fdfs_set_accept_ranges(r);
if (pResponse->content_range_len > 0)
{
fdfs_set_content_range(r, pResponse);
}
}
ngx_http_set_content_type(r);
r->headers_out.status = pResponse->status;
pResponse->header_outputed = true;
if (pResponse->content_length <= 0)
{
r->header_only = 1;
}
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_http_send_header fail, return code=%d", rc);
return;
}
}
static int fdfs_send_reply_chunk(void *arg, const bool last_buf, \
const char *buff, const int size)
{
ngx_http_request_t *r;
ngx_buf_t *b;
ngx_chain_t out;
ngx_int_t rc;
u_char *new_buff;
r = (ngx_http_request_t *)arg;
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_pcalloc fail");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
new_buff = ngx_palloc(r->pool, sizeof(u_char) * size);
if (new_buff == NULL)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_palloc fail");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
out.buf = b;
out.next = NULL;
memcpy(new_buff, buff, size);
b->pos = (u_char *)new_buff;
b->last = (u_char *)new_buff + size;
b->memory = 1;
b->last_in_chain = last_buf;
b->last_buf = last_buf;
/*
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_http_output_filter, sent: %d", r->connection->sent);
*/
rc = ngx_http_output_filter(r, &out);
if (rc == NGX_OK || rc == NGX_AGAIN)
{
return 0;
}
else
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_http_output_filter fail, return code: %d", rc);
return rc;
}
}
static int fdfs_send_reply_chunk1(void *arg, const unsigned char *buff, const size_t size)
{
ngx_http_request_t *r;
ngx_buf_t *b;
ngx_chain_t out;
ngx_int_t rc;
u_char *new_buff;
r = (ngx_http_request_t *) arg;
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pcalloc fail");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
new_buff = ngx_palloc(r->pool, sizeof(u_char) * size);
if (new_buff == NULL)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_palloc fail");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
out.buf = b;
out.next = NULL;
memcpy(new_buff, buff, size);
b->pos = (u_char *) new_buff;
b->last = (u_char *) new_buff + size;
b->memory = 1;
b->last_in_chain = 1;
b->last_buf = 1;
rc = ngx_http_output_filter(r, &out);
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_output_filter--------size %u",size);
if (rc == NGX_OK || rc == NGX_AGAIN) {
return 0;
} else {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_output_filter fail, return code: %d", rc);
return rc;
}
}
static int fdfs_send_file(void *arg, const char *filename, \
const int filename_len, const int64_t file_offset, \
const int64_t download_bytes)
{
ngx_http_request_t *r;
ngx_http_core_loc_conf_t *ccf;
ngx_buf_t *b;
ngx_str_t ngx_filename;
ngx_open_file_info_t of;
ngx_chain_t out;
ngx_uint_t level;
ngx_int_t rc;
r = (ngx_http_request_t *)arg;
ccf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_filename.data = (u_char *)filename;
ngx_filename.len = filename_len;
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
#if defined(nginx_version) && (nginx_version >= 8018)
of.read_ahead = ccf->read_ahead;
#endif
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, &ngx_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 \"%s\" failed", of.failed, filename);
}
return rc;
}
if (!of.is_file)
{
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, \
"\"%s\" is not a regular file", filename);
return NGX_HTTP_NOT_FOUND;
}
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_pcalloc fail");
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;
}
out.buf = b;
out.next = NULL;
b->file_pos = file_offset;
b->file_last = file_offset + download_bytes;
b->in_file = download_bytes > 0 ? 1 : 0;
b->file->fd = of.fd;
b->file->name.data = (u_char *)filename;
b->file->name.len = filename_len;
b->file->log = r->connection->log;
b->file->directio = of.is_directio;
b->last_in_chain = 1;
b->last_buf = 1;
rc = ngx_http_output_filter(r, &out);
if (rc == NGX_OK || rc == NGX_AGAIN)
{
return NGX_HTTP_OK;
}
else
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_http_output_filter fail, return code: %d", rc);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
static ngx_int_t ngx_http_fastdfs_proxy_create_request(ngx_http_request_t *r)
{
#define FDFS_REDIRECT_PARAM "redirect=1"
size_t len;
ngx_buf_t *b;
ngx_uint_t i;
ngx_chain_t *cl;
ngx_list_part_t *part;
ngx_table_elt_t *header;
ngx_http_upstream_t *u;
char *p;
char url[4096];
char *the_url;
size_t url_len;
bool have_query;
u = r->upstream;
if (r->valid_unparsed_uri)
{
the_url = (char *)r->unparsed_uri.data;
url_len = r->unparsed_uri.len;
have_query = memchr(the_url, '?', url_len) != NULL;
}
else
{
if (r->uri.len + r->args.len + 1 >= sizeof(url))
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"url too long, exceeds %d bytes!", (int)sizeof(url));
return NGX_ERROR;
}
p = url;
memcpy(p, r->uri.data, r->uri.len);
p += r->uri.len;
if (r->args.len > 0)
{
*p++ = '?';
memcpy(p, r->args.data, r->args.len);
p += r->args.len;
have_query = true;
}
else
{
have_query = false;
}
the_url = url;
url_len = p - url;
}
len = r->method_name.len + 1 + url_len + 1 +
sizeof(FDFS_REDIRECT_PARAM) - 1 + 1 +
sizeof(ngx_http_fastdfs_proxy_version) - 1 + sizeof(CRLF) - 1;
part = &r->headers_in.headers.part;
header = part->elts;
for (i = 0; /* void */; i++)
{
if (i >= part->nelts)
{
if (part->next == NULL)
{
break;
}
part = part->next;
header = part->elts;
i = 0;
}
len += header[i].key.len + 2 + header[i].value.len +
sizeof(CRLF) - 1;
}
b = ngx_create_temp_buf(r->pool, len);
if (b == NULL)
{
return NGX_ERROR;
}
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL)
{
return NGX_ERROR;
}
cl->buf = b;
/* the request line */
b->last = ngx_copy(b->last, r->method_name.data, r->method_name.len);
*b->last++ = ' ';
u->uri.data = b->last;
b->last = ngx_cpymem(b->last, the_url, url_len);
if (have_query)
{
*b->last++ = '&';
}
else
{
*b->last++ = '?';
}
b->last = ngx_cpymem(b->last, FDFS_REDIRECT_PARAM,
sizeof(FDFS_REDIRECT_PARAM) - 1);
u->uri.len = b->last - u->uri.data;
*b->last++ = ' ';
b->last = ngx_cpymem(b->last, ngx_http_fastdfs_proxy_version,
sizeof(ngx_http_fastdfs_proxy_version) - 1);
part = &r->headers_in.headers.part;
header = part->elts;
for (i = 0; /* void */; i++)
{
if (i >= part->nelts)
{
if (part->next == NULL)
{
break;
}
part = part->next;
header = part->elts;
i = 0;
}
b->last = ngx_copy(b->last, header[i].key.data,
header[i].key.len);
*b->last++ = ':'; *b->last++ = ' ';
b->last = ngx_copy(b->last, header[i].value.data,
header[i].value.len);
*b->last++ = CR; *b->last++ = LF;
}
/* add "\r\n" at the header end */
*b->last++ = CR; *b->last++ = LF;
/*
fprintf(stderr, "http proxy header(%d, %d):\n\"%*s\"\n",
len, b->last - b->pos, (b->last - b->pos), b->pos);
*/
ngx_log_error(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http proxy header(%d, %d):%*s",
len, b->last - b->pos, (b->last - b->pos), b->pos);
u->request_bufs = cl;
cl->next = NULL;
return NGX_OK;
}
static ngx_int_t ngx_http_fastdfs_proxy_reinit_request(ngx_http_request_t *r)
{
ngx_http_fastdfs_proxy_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_fastdfs_module);
if (ctx == NULL) {
return NGX_OK;
}
ctx->status.code = 0;
ctx->status.count = 0;
ctx->status.start = NULL;
ctx->status.end = NULL;
r->upstream->process_header = ngx_http_fastdfs_proxy_process_status_line;
r->state = 0;
return NGX_OK;
}
static void ngx_http_fastdfs_proxy_abort_request(ngx_http_request_t *r)
{
ngx_log_error(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"abort http proxy request");
return;
}
static void ngx_http_fastdfs_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
{
ngx_log_error(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"finalize http proxy request");
return;
}
static ngx_int_t ngx_http_fastdfs_proxy_process_status_line(ngx_http_request_t *r)
{
size_t len;
ngx_int_t rc;
ngx_http_upstream_t *u;
ngx_http_fastdfs_proxy_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_fastdfs_module);
if (ctx == NULL) {
return NGX_ERROR;
}
u = r->upstream;
rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
if (rc == NGX_AGAIN) {
return rc;
}
if (rc == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent no valid HTTP/1.0 header");
#if 0
if (u->accel) {
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
#endif
r->http_version = NGX_HTTP_VERSION_9;
u->state->status = NGX_HTTP_OK;
return NGX_OK;
}
if (u->state) {
u->state->status = ctx->status.code;
}
u->headers_in.status_n = ctx->status.code;
len = ctx->status.end - ctx->status.start;
u->headers_in.status_line.len = len;
u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
if (u->headers_in.status_line.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
u->process_header = ngx_http_fastdfs_proxy_process_header;
return ngx_http_fastdfs_proxy_process_header(r);
}
static ngx_int_t ngx_http_fastdfs_proxy_process_header(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_table_elt_t *h;
ngx_http_upstream_header_t *hh;
ngx_http_upstream_main_conf_t *umcf;
umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
for ( ;; ) {
rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
if (rc == NGX_OK) {
/* a header line has been parsed successfully */
h = ngx_list_push(&r->upstream->headers_in.headers);
if (h == NULL) {
return NGX_ERROR;
}
h->hash = r->header_hash;
h->key.len = r->header_name_end - r->header_name_start;
h->value.len = r->header_end - r->header_start;
h->key.data = ngx_pnalloc(r->pool,
h->key.len + 1 + h->value.len + 1 + h->key.len);
if (h->key.data == NULL) {
return NGX_ERROR;
}
h->value.data = h->key.data + h->key.len + 1;
h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
h->key.data[h->key.len] = '\0';
ngx_memcpy(h->value.data, r->header_start, h->value.len);
h->value.data[h->value.len] = '\0';
if (h->key.len == r->lowcase_index) {
ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
} else {
ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
}
hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
h->lowcase_key, h->key.len);
if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
return NGX_ERROR;
}
ngx_log_error(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http proxy header: \"%V: %V\"",
&h->key, &h->value);
continue;
}
if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
/* a whole header has been parsed successfully */
/*
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http proxy header done");
*/
/*
* if no "Server" and "Date" in header line,
* then add the special empty headers
*/
if (r->upstream->headers_in.server == NULL) {
h = ngx_list_push(&r->upstream->headers_in.headers);
if (h == NULL) {
return NGX_ERROR;
}
h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
ngx_str_set(&h->key, "Server");
ngx_str_null(&h->value);
h->lowcase_key = (u_char *) "server";
}
if (r->upstream->headers_in.date == NULL) {
h = ngx_list_push(&r->upstream->headers_in.headers);
if (h == NULL) {
return NGX_ERROR;
}
h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
ngx_str_set(&h->key, "Date");
ngx_str_null(&h->value);
h->lowcase_key = (u_char *) "date";
}
/* clear content length if response is chunked */
/*
if (r->upstream->headers_in.chunked) {
r->upstream->headers_in.content_length_n = -1;
}
*/
return NGX_OK;
}
if (rc == NGX_AGAIN) {
return NGX_AGAIN;
}
/* there was error while a header line parsing */
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent invalid header");
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
}
static int ngx_http_fastdfs_proxy_handler(void *arg, \
const char *dest_ip_addr)
{
ngx_http_request_t *r;
ngx_int_t rc;
ngx_http_upstream_t *u;
ngx_http_fastdfs_proxy_ctx_t *ctx;
ngx_http_fastdfs_loc_conf_t *plcf;
r = (ngx_http_request_t *)arg;
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_fastdfs_proxy_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_fastdfs_module);
plcf = ngx_http_get_module_loc_conf(r, ngx_http_fastdfs_module);
u = r->upstream;
#if (NGX_HTTP_SSL)
u->ssl = (plcf->upstream.ssl != NULL);
#endif
u->conf = &plcf->upstream;
u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
if (u->resolved == NULL)
{
return NGX_ERROR;
}
ngx_str_set(&u->schema, "http://");
strcpy(ctx->dest_ip_addr, dest_ip_addr);
u->resolved->host.data = (u_char *)ctx->dest_ip_addr;
u->resolved->host.len = strlen(ctx->dest_ip_addr);
u->resolved->port = (in_port_t)ntohs(((struct sockaddr_in *)r-> \
connection->local_sockaddr)->sin_port);
u->output.tag = (ngx_buf_tag_t) &ngx_http_fastdfs_module;
u->create_request = ngx_http_fastdfs_proxy_create_request;
u->reinit_request = ngx_http_fastdfs_proxy_reinit_request;
u->process_header = ngx_http_fastdfs_proxy_process_status_line;
u->abort_request = ngx_http_fastdfs_proxy_abort_request;
u->finalize_request = ngx_http_fastdfs_proxy_finalize_request;
r->state = 0;
/*
u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
if (u->pipe == NULL)
{
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
u->accel = 1;
*/
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE)
{
return rc;
}
return NGX_DONE;
}
static ngx_int_t ngx_http_fastdfs_handler(ngx_http_request_t *r)
{
struct fdfs_http_context context;
ngx_int_t rc;
char url[4096];
char *p;
if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) {
return NGX_HTTP_NOT_ALLOWED;
}
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK && rc != NGX_AGAIN)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"rc != NGX_OK && rc != NGX_AGAIN nooooooooooooooo");
return rc;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,"rc != NGX_OK && rc != NGX_AGAIN okkkkkkkkkkk");
if (r->uri.len + r->args.len + 1 >= sizeof(url))
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"url too long, exceeds %d bytes!", (int)sizeof(url));
return HTTP_BADREQUEST;
}
p = url;
memcpy(p, r->uri.data, r->uri.len);
p += r->uri.len;
if (r->args.len > 0)
{
*p++ = '?';
memcpy(p, r->args.data, r->args.len);
p += r->args.len;
}
*p = '\0';
memset(&context, 0, sizeof(context));
context.arg = r;
context.header_only = (r->method & NGX_HTTP_HEAD) ? 1 : 0;
context.url = url;
context.output_headers = fdfs_output_headers;
context.send_file = fdfs_send_file;
context.send_reply_chunk = fdfs_send_reply_chunk;
context.send_reply_chunk1 = fdfs_send_reply_chunk1;
context.proxy_handler = ngx_http_fastdfs_proxy_handler;
context.server_port = ntohs(((struct sockaddr_in *)r->connection-> \
local_sockaddr)->sin_port);
if (r->headers_in.if_modified_since != NULL)
{
if (r->headers_in.if_modified_since->value.len < \
sizeof(context.if_modified_since))
{
memcpy(context.if_modified_since, \
r->headers_in.if_modified_since->value.data, \
r->headers_in.if_modified_since->value.len);
}
/*
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, \
"if_modified_since: %s", context.if_modified_since);
*/
}
if (r->headers_in.range != NULL)
{
char buff[64];
if (r->headers_in.range->value.len >= sizeof(buff))
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, \
"bad request, range length: %d exceeds buff " \
"size: %d, range: %*s", \
r->headers_in.range->value.len, \
(int)sizeof(buff), \
r->headers_in.range->value.len, \
r->headers_in.range->value.data);
return NGX_HTTP_BAD_REQUEST;
}
memcpy(buff, r->headers_in.range->value.data, \
r->headers_in.range->value.len);
*(buff + r->headers_in.range->value.len) = '\0';
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "buff=%s", buff);
if (fdfs_parse_range(buff, &(context.range)) != 0)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, \
"bad request, invalid range: %s", buff);
return NGX_HTTP_BAD_REQUEST;
}
context.if_range = true;
/*
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, \
"if_range=%d, start=%d, end=%d", context.if_range, \
(int)context.range.start, (int)context.range.end);
*/
}
/*
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, \
"args=%*s, uri=%*s", r->args.len, r->args.data, \
r->uri.len, r->uri.data);
*/
return fdfs_http_request_handler(&context);
}
static char *ngx_http_fastdfs_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf = ngx_http_conf_get_module_loc_conf(cf, \
ngx_http_core_module);
fprintf(stderr, "ngx_http_fastdfs_set pid=%d\n", getpid());
/* register hanlder */
clcf->handler = ngx_http_fastdfs_handler;
return NGX_CONF_OK;
}
static ngx_int_t ngx_http_fastdfs_process_init(ngx_cycle_t *cycle)
{
int result;
fprintf(stderr, "ngx_http_fastdfs_process_init pid=%d\n", getpid());
// do some init here
if ((result=fdfs_mod_init()) != 0)
{
return NGX_ERROR;
}
return NGX_OK;
}
static void ngx_http_fastdfs_process_exit(ngx_cycle_t *cycle)
{
fprintf(stderr, "ngx_http_fastdfs_process_exit pid=%d\n", getpid());
return;
}
static void *ngx_http_fastdfs_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_fastdfs_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastdfs_loc_conf_t));
if (conf == NULL) {
return NULL;
}
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
/* the hardcoded values */
conf->upstream.cyclic_temp_file = 0;
conf->upstream.buffering = 0;
conf->upstream.ignore_client_abort = 0;
conf->upstream.send_lowat = 0;
conf->upstream.bufs.num = 0;
conf->upstream.busy_buffers_size = 0;
conf->upstream.max_temp_file_size = 0;
conf->upstream.temp_file_write_size = 0;
conf->upstream.intercept_errors = 1;
conf->upstream.intercept_404 = 1;
conf->upstream.pass_request_headers = 0;
conf->upstream.pass_request_body = 0;
conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
return conf;
}
static char * ngx_http_fastdfs_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_hash_init_t hash;
ngx_http_fastdfs_loc_conf_t *prev = parent;
ngx_http_fastdfs_loc_conf_t *conf = child;
ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
prev->upstream.connect_timeout, 60000);
ngx_conf_merge_msec_value(conf->upstream.send_timeout,
prev->upstream.send_timeout, 60000);
ngx_conf_merge_msec_value(conf->upstream.read_timeout,
prev->upstream.read_timeout, 60000);
ngx_conf_merge_size_value(conf->upstream.buffer_size,
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
prev->upstream.next_upstream,
(NGX_CONF_BITMASK_SET
|NGX_HTTP_UPSTREAM_FT_ERROR
|NGX_HTTP_UPSTREAM_FT_TIMEOUT));
if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
|NGX_HTTP_UPSTREAM_FT_OFF;
}
if (conf->upstream.upstream == NULL) {
conf->upstream.upstream = prev->upstream.upstream;
}
ngx_conf_merge_uint_value(conf->headers_hash_max_size,
prev->headers_hash_max_size, 512);
ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
prev->headers_hash_bucket_size, 64);
conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
ngx_cacheline_size);
hash.max_size = conf->headers_hash_max_size;
hash.bucket_size = conf->headers_hash_bucket_size;
hash.name = "proxy_headers_hash";
if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
&prev->upstream, ngx_http_proxy_hide_headers, &hash)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}