378 lines
9.0 KiB
C
Executable File
378 lines
9.0 KiB
C
Executable File
|
|
/**
|
|
* 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.fastken.com/ for more detail.
|
|
**/
|
|
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <netinet/in.h>
|
|
#include <fcntl.h>
|
|
#include "fastcommon/logger.h"
|
|
#include "fastcommon/md5.h"
|
|
#include "fastcommon/shared_func.h"
|
|
#include "mime_file_parser.h"
|
|
#include "fdfs_global.h"
|
|
#include "fdfs_http_shared.h"
|
|
|
|
const char *fdfs_http_get_file_extension(const char *filename, \
|
|
const int filename_len, int *ext_len)
|
|
{
|
|
const char *pEnd;
|
|
const char *pExtName;
|
|
int i;
|
|
|
|
pEnd = filename + filename_len;
|
|
pExtName = pEnd - 1;
|
|
for (i=0; i<FDFS_FILE_EXT_NAME_MAX_LEN && pExtName >= filename; \
|
|
i++, pExtName--)
|
|
{
|
|
if (*pExtName == '.')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i < FDFS_FILE_EXT_NAME_MAX_LEN) //found
|
|
{
|
|
pExtName++; //skip .
|
|
*ext_len = pEnd - pExtName;
|
|
return pExtName;
|
|
}
|
|
else
|
|
{
|
|
*ext_len = 0;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int fdfs_http_get_content_type_by_extname(FDFSHTTPParams *pParams, \
|
|
const char *ext_name, const int ext_len, \
|
|
char *content_type, const int content_type_size)
|
|
{
|
|
HashData *pHashData;
|
|
|
|
if (ext_len == 0)
|
|
{
|
|
logWarning("file: "__FILE__", line: %d, " \
|
|
"extension name is empty, " \
|
|
"set to default content type: %s", \
|
|
__LINE__, pParams->default_content_type);
|
|
strcpy(content_type, pParams->default_content_type);
|
|
return 0;
|
|
}
|
|
|
|
pHashData = hash_find_ex(&pParams->content_type_hash, \
|
|
ext_name, ext_len + 1);
|
|
if (pHashData == NULL)
|
|
{
|
|
logWarning("file: "__FILE__", line: %d, " \
|
|
"extension name: %s is not supported, " \
|
|
"set to default content type: %s", \
|
|
__LINE__, ext_name, pParams->default_content_type);
|
|
strcpy(content_type, pParams->default_content_type);
|
|
return 0;
|
|
}
|
|
|
|
if (pHashData->value_len >= content_type_size)
|
|
{
|
|
*content_type = '\0';
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"extension name: %s 's content type " \
|
|
"is too long", __LINE__, ext_name);
|
|
return EINVAL;
|
|
}
|
|
|
|
memcpy(content_type, pHashData->value, pHashData->value_len);
|
|
return 0;
|
|
}
|
|
|
|
int fdfs_http_params_load(IniContext *pIniContext, \
|
|
const char *conf_filename, FDFSHTTPParams *pParams)
|
|
{
|
|
int result;
|
|
int ext_len;
|
|
const char *ext_name;
|
|
char *mime_types_filename;
|
|
char szMimeFilename[256];
|
|
char *anti_steal_secret_key;
|
|
char *token_check_fail_filename;
|
|
char *default_content_type;
|
|
int def_content_type_len;
|
|
int64_t file_size;
|
|
|
|
memset(pParams, 0, sizeof(FDFSHTTPParams));
|
|
|
|
pParams->disabled = iniGetBoolValue(NULL, "http.disabled", \
|
|
pIniContext, false);
|
|
if (pParams->disabled)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
pParams->need_find_content_type = iniGetBoolValue(NULL, \
|
|
"http.need_find_content_type", \
|
|
pIniContext, true);
|
|
|
|
pParams->support_multi_range = iniGetBoolValue(NULL, \
|
|
"http.multi_range.enabed", \
|
|
pIniContext, true);
|
|
|
|
pParams->server_port = iniGetIntValue(NULL, "http.server_port", \
|
|
pIniContext, 80);
|
|
if (pParams->server_port <= 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"invalid param \"http.server_port\": %d", \
|
|
__LINE__, pParams->server_port);
|
|
return EINVAL;
|
|
}
|
|
|
|
pParams->anti_steal_token = iniGetBoolValue(NULL, \
|
|
"http.anti_steal.check_token", \
|
|
pIniContext, false);
|
|
if (pParams->need_find_content_type || pParams->anti_steal_token ||
|
|
pParams->support_multi_range)
|
|
{
|
|
mime_types_filename = iniGetStrValue(NULL, "http.mime_types_filename", \
|
|
pIniContext);
|
|
if (mime_types_filename == NULL || *mime_types_filename == '\0')
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"param \"http.mime_types_filename\" not exist " \
|
|
"or is empty", __LINE__);
|
|
return EINVAL;
|
|
}
|
|
|
|
if (strncasecmp(mime_types_filename, "http://", 7) != 0 && \
|
|
*mime_types_filename != '/' && \
|
|
strncasecmp(conf_filename, "http://", 7) != 0)
|
|
{
|
|
char *pPathEnd;
|
|
|
|
pPathEnd = strrchr(conf_filename, '/');
|
|
if (pPathEnd == NULL)
|
|
{
|
|
snprintf(szMimeFilename, sizeof(szMimeFilename), \
|
|
"%s", mime_types_filename);
|
|
}
|
|
else
|
|
{
|
|
int nPathLen;
|
|
int nFilenameLen;
|
|
|
|
nPathLen = (pPathEnd - conf_filename) + 1;
|
|
nFilenameLen = strlen(mime_types_filename);
|
|
if (nPathLen + nFilenameLen >= sizeof(szMimeFilename))
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"filename is too long, length %d >= %d",
|
|
__LINE__, nPathLen + nFilenameLen, \
|
|
(int)sizeof(szMimeFilename));
|
|
return ENOSPC;
|
|
}
|
|
|
|
memcpy(szMimeFilename, conf_filename, nPathLen);
|
|
memcpy(szMimeFilename + nPathLen, mime_types_filename, \
|
|
nFilenameLen);
|
|
*(szMimeFilename + nPathLen + nFilenameLen) = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
snprintf(szMimeFilename, sizeof(szMimeFilename), \
|
|
"%s", mime_types_filename);
|
|
}
|
|
|
|
result = load_mime_types_from_file(&pParams->content_type_hash, \
|
|
szMimeFilename);
|
|
if (result != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
default_content_type = iniGetStrValue(NULL, \
|
|
"http.default_content_type", \
|
|
pIniContext);
|
|
if (default_content_type == NULL || *default_content_type == '\0')
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"param \"http.default_content_type\" not exist " \
|
|
"or is empty", __LINE__);
|
|
return EINVAL;
|
|
}
|
|
|
|
def_content_type_len = strlen(default_content_type);
|
|
if (def_content_type_len >= sizeof(pParams->default_content_type))
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"default content type: %s is too long", \
|
|
__LINE__, default_content_type);
|
|
return EINVAL;
|
|
}
|
|
memcpy(pParams->default_content_type, default_content_type, \
|
|
def_content_type_len);
|
|
}
|
|
|
|
if (!pParams->anti_steal_token)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
pParams->token_ttl = iniGetIntValue(NULL, \
|
|
"http.anti_steal.token_ttl", \
|
|
pIniContext, 600);
|
|
if (pParams->token_ttl <= 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"param \"http.anti_steal.token_ttl\" is invalid", \
|
|
__LINE__);
|
|
return EINVAL;
|
|
}
|
|
|
|
anti_steal_secret_key = iniGetStrValue(NULL, \
|
|
"http.anti_steal.secret_key", \
|
|
pIniContext);
|
|
if (anti_steal_secret_key == NULL || *anti_steal_secret_key == '\0')
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"param \"http.anti_steal.secret_key\" not exist " \
|
|
"or is empty", __LINE__);
|
|
return EINVAL;
|
|
}
|
|
|
|
buffer_strcpy(&pParams->anti_steal_secret_key, anti_steal_secret_key);
|
|
|
|
token_check_fail_filename = iniGetStrValue(NULL, \
|
|
"http.anti_steal.token_check_fail", \
|
|
pIniContext);
|
|
if (token_check_fail_filename == NULL || \
|
|
*token_check_fail_filename == '\0')
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (!fileExists(token_check_fail_filename))
|
|
{
|
|
logError("file: "__FILE__", line: %d, " \
|
|
"token_check_fail file: %s not exists", __LINE__, \
|
|
token_check_fail_filename);
|
|
return ENOENT;
|
|
}
|
|
|
|
ext_name = fdfs_http_get_file_extension(token_check_fail_filename, \
|
|
strlen(token_check_fail_filename), &ext_len);
|
|
if ((result=fdfs_http_get_content_type_by_extname(pParams, \
|
|
ext_name, ext_len, \
|
|
pParams->token_check_fail_content_type, \
|
|
sizeof(pParams->token_check_fail_content_type))) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (!(pParams->need_find_content_type || pParams->support_multi_range))
|
|
{
|
|
hash_destroy(&pParams->content_type_hash);
|
|
}
|
|
|
|
if ((result=getFileContent(token_check_fail_filename, \
|
|
&pParams->token_check_fail_buff.buff, &file_size)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
pParams->token_check_fail_buff.alloc_size = file_size;
|
|
pParams->token_check_fail_buff.length = file_size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void fdfs_http_params_destroy(FDFSHTTPParams *pParams)
|
|
{
|
|
if (!(pParams->need_find_content_type || pParams->support_multi_range))
|
|
{
|
|
hash_destroy(&pParams->content_type_hash);
|
|
}
|
|
}
|
|
|
|
int fdfs_http_gen_token(const BufferInfo *secret_key, const char *file_id, \
|
|
const int timestamp, char *token)
|
|
{
|
|
char buff[256 + 64];
|
|
unsigned char digit[16];
|
|
int id_len;
|
|
int total_len;
|
|
|
|
id_len = strlen(file_id);
|
|
if (id_len + secret_key->length + 12 > sizeof(buff))
|
|
{
|
|
return ENOSPC;
|
|
}
|
|
|
|
memcpy(buff, file_id, id_len);
|
|
total_len = id_len;
|
|
memcpy(buff + total_len, secret_key->buff, secret_key->length);
|
|
total_len += secret_key->length;
|
|
total_len += sprintf(buff + total_len, "%d", timestamp);
|
|
|
|
my_md5_buffer(buff, total_len, digit);
|
|
bin2hex((char *)digit, 16, token);
|
|
return 0;
|
|
}
|
|
|
|
int fdfs_http_check_token(const BufferInfo *secret_key, const char *file_id, \
|
|
const int timestamp, const char *token, const int ttl)
|
|
{
|
|
char true_token[33];
|
|
int result;
|
|
int token_len;
|
|
|
|
token_len = strlen(token);
|
|
if (token_len != 32)
|
|
{
|
|
return EINVAL;
|
|
}
|
|
|
|
if ((timestamp != 0) && (time(NULL) - timestamp > ttl))
|
|
{
|
|
return ETIMEDOUT;
|
|
}
|
|
|
|
if ((result=fdfs_http_gen_token(secret_key, file_id, \
|
|
timestamp, true_token)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
return (memcmp(token, true_token, 32) == 0) ? 0 : EPERM;
|
|
}
|
|
|
|
char *fdfs_http_get_parameter(const char *param_name, KeyValuePair *params, \
|
|
const int param_count)
|
|
{
|
|
KeyValuePair *pCurrent;
|
|
KeyValuePair *pEnd;
|
|
|
|
pEnd = params + param_count;
|
|
for (pCurrent=params; pCurrent<pEnd; pCurrent++)
|
|
{
|
|
if (strcmp(pCurrent->key, param_name) == 0)
|
|
{
|
|
return pCurrent->value;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|