Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
F
freeswitch
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
张华
freeswitch
Commits
8c8b2176
提交
8c8b2176
authored
5月 20, 2013
作者:
Chris Rienzo
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
mod_http_cache: added native Amazon S3 support
上级
fe000f18
隐藏空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
798 行增加
和
34 行删除
+798
-34
Makefile
src/mod/applications/mod_http_cache/Makefile
+5
-0
aws.c
src/mod/applications/mod_http_cache/aws.c
+238
-0
aws.h
src/mod/applications/mod_http_cache/aws.h
+55
-0
http_cache.conf.xml
.../mod_http_cache/conf/autoload_configs/http_cache.conf.xml
+15
-0
mod_http_cache.c
src/mod/applications/mod_http_cache/mod_http_cache.c
+223
-34
Makefile
src/mod/applications/mod_http_cache/test_aws/Makefile
+12
-0
main.c
src/mod/applications/mod_http_cache/test_aws/main.c
+131
-0
test.h
src/mod/applications/mod_http_cache/test_aws/test.h
+113
-0
test_aws.c
src/mod/applications/mod_http_cache/test_aws/test_aws.c
+6
-0
没有找到文件。
src/mod/applications/mod_http_cache/Makefile
浏览文件 @
8c8b2176
BASE
=
../../../..
LOCAL_OBJS
=
\
aws.o
LOCAL_SOURCES
=
\
aws.c
include
$(BASE)/build/modmake.rules
src/mod/applications/mod_http_cache/aws.c
0 → 100644
浏览文件 @
8c8b2176
/*
* aws.c for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2013, Grasshopper
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is aws.c for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is Grasshopper
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Rienzo <chris.rienzo@grasshopper.com>
*
* aws.c -- Some Amazon Web Services helper functions
*
*/
#include "aws.h"
#include <switch.h>
#if defined(HAVE_OPENSSL)
#include <openssl/hmac.h>
#include <openssl/sha.h>
#endif
/* 160 bits / 8 bits per byte */
#define SHA1_LENGTH 20
/**
* @param url to check
* @return true if this is an S3 url
*/
int
aws_s3_is_s3_url
(
const
char
*
url
)
{
/* AWS bucket naming rules are complex... this match only supports virtual hosting of buckets */
return
!
zstr
(
url
)
&&
switch_regex_match
(
url
,
"^https?://[a-z0-9][-a-z0-9.]{1,61}[a-z0-9]
\\
.s3
\\
.amazonaws
\\
.com/.*$"
)
==
SWITCH_STATUS_SUCCESS
;
}
/**
* Create the string to sign for a AWS signature calculation
* @param verb (PUT/GET)
* @param bucket bucket object is stored in
* @param object to access (filename.ext)
* @param content_type optional content type
* @param content_md5 optional content MD5 checksum
* @param date header
* @return the string_to_sign (must be freed)
*/
char
*
aws_s3_string_to_sign
(
const
char
*
verb
,
const
char
*
bucket
,
const
char
*
object
,
const
char
*
content_type
,
const
char
*
content_md5
,
const
char
*
date
)
{
/*
* String to sign has the following format:
* <HTTP-VERB>\n<Content-MD5>\n<Content-Type>\n<Expires/Date>\n/bucket/object
*/
return
switch_mprintf
(
"%s
\n
%s
\n
%s
\n
%s
\n
/%s/%s"
,
verb
,
content_md5
?
content_md5
:
""
,
content_type
?
content_type
:
""
,
date
,
bucket
,
object
);
}
/**
* Create the AWS S3 signature
* @param signature buffer to store the signature
* @param signature_length length of signature buffer
* @param string_to_sign
* @param aws_secret_access_key secret access key
* @return the signature buffer or NULL if missing input
*/
char
*
aws_s3_signature
(
char
*
signature
,
int
signature_length
,
const
char
*
string_to_sign
,
const
char
*
aws_secret_access_key
)
{
#if defined(HAVE_OPENSSL)
unsigned
int
signature_raw_length
=
SHA1_LENGTH
;
char
signature_raw
[
SHA1_LENGTH
];
signature_raw
[
0
]
=
'\0'
;
if
(
!
signature
||
signature_length
<=
0
)
{
return
NULL
;
}
if
(
zstr
(
aws_secret_access_key
))
{
return
NULL
;
}
if
(
!
string_to_sign
)
{
string_to_sign
=
""
;
}
HMAC
(
EVP_sha1
(),
aws_secret_access_key
,
strlen
(
aws_secret_access_key
),
(
const
unsigned
char
*
)
string_to_sign
,
strlen
(
string_to_sign
),
(
unsigned
char
*
)
signature_raw
,
&
signature_raw_length
);
/* convert result to base64 */
memset
(
signature
,
0
,
signature_length
);
switch_b64_encode
((
unsigned
char
*
)
signature_raw
,
signature_raw_length
,
(
unsigned
char
*
)
signature
,
signature_length
);
#endif
return
signature
;
}
/**
* Parse bucket and object from URL
* @param url to parse. This value is modified.
* @param bucket to store result in
* @param bucket_length of result buffer
*/
void
aws_s3_parse_url
(
char
*
url
,
char
**
bucket
,
char
**
object
)
{
char
*
bucket_start
;
char
*
bucket_end
;
char
*
object_start
;
*
bucket
=
NULL
;
*
object
=
NULL
;
if
(
!
aws_s3_is_s3_url
(
url
))
{
return
;
}
/* expect: http(s)://bucket.s3.amazonaws.com/object */
bucket_start
=
strstr
(
url
,
"://"
);
if
(
!
bucket_start
)
{
/* invalid URL */
return
;
}
bucket_start
+=
3
;
bucket_end
=
strchr
(
bucket_start
,
'.'
);
if
(
!
bucket_end
)
{
/* invalid URL */
return
;
}
*
bucket_end
=
'\0'
;
object_start
=
strchr
(
bucket_end
+
1
,
'/'
);
if
(
!
object_start
)
{
/* invalid URL */
return
;
}
object_start
++
;
if
(
strchr
(
object_start
,
'/'
))
{
/* invalid URL */
return
;
}
if
(
zstr
(
bucket_start
)
||
zstr
(
object_start
))
{
/* invalid URL */
return
;
}
*
bucket
=
bucket_start
;
*
object
=
object_start
;
}
/**
* Create a pre-signed URL for AWS S3
* @param verb (PUT/GET)
* @param url address (virtual-host-style)
* @param content_type optional content type
* @param content_md5 optional content MD5 checksum
* @param aws_access_key_id secret access key identifier
* @param aws_secret_access_key secret access key
* @param expires seconds since the epoch
* @return presigned_url
*/
char
*
aws_s3_presigned_url_create
(
const
char
*
verb
,
const
char
*
url
,
const
char
*
content_type
,
const
char
*
content_md5
,
const
char
*
aws_access_key_id
,
const
char
*
aws_secret_access_key
,
const
char
*
expires
)
{
char
signature
[
S3_SIGNATURE_LENGTH_MAX
];
char
signature_url_encoded
[
S3_SIGNATURE_LENGTH_MAX
];
char
*
string_to_sign
;
char
*
url_dup
=
strdup
(
url
);
char
*
bucket
;
char
*
object
;
/* create URL encoded signature */
aws_s3_parse_url
(
url_dup
,
&
bucket
,
&
object
);
string_to_sign
=
aws_s3_string_to_sign
(
verb
,
bucket
,
object
,
content_type
,
content_md5
,
expires
);
signature
[
0
]
=
'\0'
;
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
string_to_sign
,
aws_secret_access_key
);
switch_url_encode
(
signature
,
signature_url_encoded
,
S3_SIGNATURE_LENGTH_MAX
);
free
(
string_to_sign
);
free
(
url_dup
);
/* create the presigned URL */
return
switch_mprintf
(
"%s?Signature=%s&Expires=%s&AWSAccessKeyId=%s"
,
url
,
signature_url_encoded
,
expires
,
aws_access_key_id
);
}
/**
* Create an authentication signature for AWS S3
* @param authentication buffer to store result
* @param authentication_length maximum result length
* @param verb (PUT/GET)
* @param url address (virtual-host-style)
* @param content_type optional content type
* @param content_md5 optional content MD5 checksum
* @param aws_access_key_id secret access key identifier
* @param aws_secret_access_key secret access key
* @param date header
* @return signature for Authorization header
*/
char
*
aws_s3_authentication_create
(
const
char
*
verb
,
const
char
*
url
,
const
char
*
content_type
,
const
char
*
content_md5
,
const
char
*
aws_access_key_id
,
const
char
*
aws_secret_access_key
,
const
char
*
date
)
{
char
signature
[
S3_SIGNATURE_LENGTH_MAX
];
char
*
string_to_sign
;
char
*
url_dup
=
strdup
(
url
);
char
*
bucket
;
char
*
object
;
/* create base64 encoded signature */
aws_s3_parse_url
(
url_dup
,
&
bucket
,
&
object
);
string_to_sign
=
aws_s3_string_to_sign
(
verb
,
bucket
,
object
,
content_type
,
content_md5
,
date
);
signature
[
0
]
=
'\0'
;
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
string_to_sign
,
aws_secret_access_key
);
free
(
string_to_sign
);
free
(
url_dup
);
return
switch_mprintf
(
"AWS %s:%s"
,
aws_access_key_id
,
signature
);
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
*/
src/mod/applications/mod_http_cache/aws.h
0 → 100644
浏览文件 @
8c8b2176
/*
* aws.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2013, Grasshopper
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is aws.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is Grasshopper
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Rienzo <chris.rienzo@grasshopper.com>
*
* aws.h - Some Amazon Web Services helper functions
*
*/
#ifndef AWS_H
#define AWS_H
#include <switch.h>
/* (SHA1_LENGTH * 1.37 base64 bytes per byte * 3 url-encoded bytes per byte) */
#define S3_SIGNATURE_LENGTH_MAX 83
int
aws_s3_is_s3_url
(
const
char
*
url
);
void
aws_s3_parse_url
(
char
*
url
,
char
**
bucket
,
char
**
object
);
char
*
aws_s3_string_to_sign
(
const
char
*
verb
,
const
char
*
bucket
,
const
char
*
object
,
const
char
*
content_type
,
const
char
*
content_md5
,
const
char
*
date
);
char
*
aws_s3_signature
(
char
*
signature
,
int
signature_length
,
const
char
*
string_to_sign
,
const
char
*
aws_secret_access_key
);
char
*
aws_s3_presigned_url_create
(
const
char
*
verb
,
const
char
*
url
,
const
char
*
content_type
,
const
char
*
content_md5
,
const
char
*
aws_access_key_id
,
const
char
*
aws_secret_access_key
,
const
char
*
expires
);
char
*
aws_s3_authentication_create
(
const
char
*
verb
,
const
char
*
url
,
const
char
*
content_type
,
const
char
*
content_md5
,
const
char
*
aws_access_key_id
,
const
char
*
aws_secret_access_key
,
const
char
*
date
);
#endif
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
*/
src/mod/applications/mod_http_cache/conf/autoload_configs/http_cache.conf.xml
浏览文件 @
8c8b2176
...
...
@@ -9,4 +9,19 @@
<param
name=
"ssl-verifyhost"
value=
"true"
/>
<param
name=
"ssl-verifypeer"
value=
"true"
/>
</settings>
<profiles>
<profile
name=
"s3"
>
<!-- Credentials for AWS account. Reference by name when sending HTTP request -->
<!-- http_get {profile=s3}http://bucket.s3.amazonaws.com/object.wav -->
<!-- http_put {profile=s3}http://bucket.s3.amazonaws.com/object.wav /tmp/file.wav -->
<aws-s3>
<!-- 20 character key identifier -->
<access-key-id>
<![CDATA[AKIAIOSFODNN7EXAMPLE]]>
</access-key-id>
<!-- 40 character secret -->
<secret-access-key>
<![CDATA[wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY]]>
</secret-access-key>
<aws-s3>
</profile>
</profiles>
</configuration>
src/mod/applications/mod_http_cache/mod_http_cache.c
浏览文件 @
8c8b2176
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-201
2
, Anthony Minessale II <anthm@freeswitch.org>
* Copyright (C) 2005-201
3
, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
...
...
@@ -34,6 +34,7 @@
*/
#include <switch.h>
#include <switch_curl.h>
#include "aws.h"
/* Defines module interface to FreeSWITCH */
SWITCH_MODULE_SHUTDOWN_FUNCTION
(
mod_http_cache_shutdown
);
...
...
@@ -49,6 +50,17 @@ SWITCH_STANDARD_API(http_cache_prefetch);
typedef
struct
url_cache
url_cache_t
;
/**
* An http profile. Defines optional credentials
* for access to Amazon S3.
*/
struct
http_profile
{
const
char
*
name
;
const
char
*
aws_s3_access_key_id
;
const
char
*
aws_s3_secret_access_key
;
};
typedef
struct
http_profile
http_profile_t
;
/**
* status if the cache entry
*/
...
...
@@ -99,12 +111,12 @@ struct http_get_data {
};
typedef
struct
http_get_data
http_get_data_t
;
static
switch_status_t
http_get
(
url_cache_t
*
cache
,
cached_url_t
*
url
,
switch_core_session_t
*
session
);
static
switch_status_t
http_get
(
url_cache_t
*
cache
,
http_profile_t
*
profile
,
cached_url_t
*
url
,
switch_core_session_t
*
session
);
static
size_t
get_file_callback
(
void
*
ptr
,
size_t
size
,
size_t
nmemb
,
void
*
get
);
static
size_t
get_header_callback
(
void
*
ptr
,
size_t
size
,
size_t
nmemb
,
void
*
url
);
static
void
process_cache_control_header
(
cached_url_t
*
url
,
char
*
data
);
static
switch_status_t
http_put
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
,
const
char
*
url
,
const
char
*
filename
);
static
switch_status_t
http_put
(
url_cache_t
*
cache
,
http_profile_t
*
profile
,
switch_core_session_t
*
session
,
const
char
*
url
,
const
char
*
filename
);
/**
* Queue used for clock cache replacement algorithm. This
...
...
@@ -123,7 +135,6 @@ struct simple_queue {
};
typedef
struct
simple_queue
simple_queue_t
;
/**
* The cache
*/
...
...
@@ -138,6 +149,8 @@ struct url_cache {
size_t
size
;
/** The location of the cache in the filesystem */
char
*
location
;
/** HTTP profiles */
switch_hash_t
*
profiles
;
/** Cache mapped by URL */
switch_hash_t
*
map
;
/** Cached URLs queued for replacement */
...
...
@@ -173,7 +186,7 @@ struct url_cache {
};
static
url_cache_t
gcache
;
static
char
*
url_cache_get
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
,
const
char
*
url
,
int
download
,
switch_memory_pool_t
*
pool
);
static
char
*
url_cache_get
(
url_cache_t
*
cache
,
http_profile_t
*
profile
,
switch_core_session_t
*
session
,
const
char
*
url
,
int
download
,
switch_memory_pool_t
*
pool
);
static
switch_status_t
url_cache_add
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
,
cached_url_t
*
url
);
static
void
url_cache_remove
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
,
cached_url_t
*
url
);
static
void
url_cache_remove_soft
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
,
cached_url_t
*
url
);
...
...
@@ -181,16 +194,21 @@ static switch_status_t url_cache_replace(url_cache_t *cache, switch_core_session
static
void
url_cache_lock
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
);
static
void
url_cache_unlock
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
);
static
void
url_cache_clear
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
);
static
http_profile_t
*
url_cache_http_profile_find
(
url_cache_t
*
cache
,
const
char
*
name
);
static
void
url_cache_http_profile_add
(
url_cache_t
*
cache
,
const
char
*
name
,
const
char
*
aws_s3_access_key_id
,
const
char
*
aws_s3_secret_access_key
);
static
switch_curl_slist_t
*
append_aws_s3_headers
(
switch_curl_slist_t
*
headers
,
http_profile_t
*
profile
,
const
char
*
verb
,
const
char
*
content_type
,
const
char
*
url
);
/**
* Put a file to the URL
* @param cache the cache
* @param profile the HTTP profile
* @param session the (optional) session uploading the file
* @param url The URL
* @param filename The file to upload
* @return SWITCH_STATUS_SUCCESS if successful
*/
static
switch_status_t
http_put
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
,
const
char
*
url
,
const
char
*
filename
)
static
switch_status_t
http_put
(
url_cache_t
*
cache
,
http_profile_t
*
profile
,
switch_core_session_t
*
session
,
const
char
*
url
,
const
char
*
filename
)
{
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
...
...
@@ -215,6 +233,7 @@ static switch_status_t http_put(url_cache_t *cache, switch_core_session_t *sessi
buf
=
switch_mprintf
(
"Content-Type: %s"
,
mime_type
);
headers
=
switch_curl_slist_append
(
headers
,
buf
);
headers
=
append_aws_s3_headers
(
headers
,
profile
,
"PUT"
,
mime_type
,
url
);
/* open file and get the file size */
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_DEBUG
,
"opening %s for upload to %s
\n
"
,
filename
,
url
);
...
...
@@ -316,6 +335,7 @@ static size_t get_file_callback(void *ptr, size_t size, size_t nmemb, void *get)
return
result
;
}
/**
* trim whitespace characters from string
* @param str the string to trim
...
...
@@ -492,13 +512,14 @@ static void url_cache_clear(url_cache_t *cache, switch_core_session_t *session)
/**
* Get a URL from the cache, add it if it does not exist
* @param cache The cache
* @param profile optional profile
* @param session the (optional) session requesting the URL
* @param url The URL
* @param download If true, the file will be downloaded if it does not exist in the cache.
* @param pool The pool to use for allocating the filename
* @return The filename or NULL if there is an error
*/
static
char
*
url_cache_get
(
url_cache_t
*
cache
,
switch_core_session_t
*
session
,
const
char
*
url
,
int
download
,
switch_memory_pool_t
*
pool
)
static
char
*
url_cache_get
(
url_cache_t
*
cache
,
http_profile_t
*
profile
,
switch_core_session_t
*
session
,
const
char
*
url
,
int
download
,
switch_memory_pool_t
*
pool
)
{
char
*
filename
=
NULL
;
cached_url_t
*
u
=
NULL
;
...
...
@@ -537,7 +558,7 @@ static char *url_cache_get(url_cache_t *cache, switch_core_session_t *session, c
/* download the file */
url_cache_unlock
(
cache
,
session
);
if
(
http_get
(
cache
,
u
,
session
)
==
SWITCH_STATUS_SUCCESS
)
{
if
(
http_get
(
cache
,
profile
,
u
,
session
)
==
SWITCH_STATUS_SUCCESS
)
{
/* Got the file, let the waiters know it is available */
url_cache_lock
(
cache
,
session
);
u
->
status
=
CACHED_URL_AVAILABLE
;
...
...
@@ -685,6 +706,33 @@ static void url_cache_remove(url_cache_t *cache, switch_core_session_t *session,
cache
->
size
-=
url
->
size
;
}
/**
* Find a profile
*/
static
http_profile_t
*
url_cache_http_profile_find
(
url_cache_t
*
cache
,
const
char
*
name
)
{
if
(
cache
&&
!
zstr
(
name
))
{
return
(
http_profile_t
*
)
switch_core_hash_find
(
cache
->
profiles
,
name
);
}
return
NULL
;
}
/**
* Add a profile to the cache
*/
static
void
url_cache_http_profile_add
(
url_cache_t
*
cache
,
const
char
*
name
,
const
char
*
aws_s3_access_key_id
,
const
char
*
aws_s3_secret_access_key
)
{
http_profile_t
*
profile
=
switch_core_alloc
(
cache
->
pool
,
sizeof
(
*
profile
));
profile
->
name
=
switch_core_strdup
(
cache
->
pool
,
name
);
if
(
aws_s3_access_key_id
)
{
profile
->
aws_s3_access_key_id
=
switch_core_strdup
(
cache
->
pool
,
aws_s3_access_key_id
);
}
if
(
aws_s3_secret_access_key
)
{
profile
->
aws_s3_secret_access_key
=
switch_core_strdup
(
cache
->
pool
,
aws_s3_secret_access_key
);
}
switch_core_hash_insert
(
cache
->
profiles
,
profile
->
name
,
profile
);
}
/**
* Create a cached URL entry
* @param cache the cache
...
...
@@ -759,16 +807,49 @@ static void cached_url_destroy(cached_url_t *url, switch_memory_pool_t *pool)
switch_safe_free
(
url
);
}
/**
* Append Amazon S3 headers to request if necessary
* @param headers to add to. If NULL, new headers are created.
* @param profile with S3 credentials
* @param content_type of object (PUT only)
* @param verb (GET/PUT)
* @param url
* @return updated headers
*/
static
switch_curl_slist_t
*
append_aws_s3_headers
(
switch_curl_slist_t
*
headers
,
http_profile_t
*
profile
,
const
char
*
verb
,
const
char
*
content_type
,
const
char
*
url
)
{
/* check if Amazon headers are needed */
if
(
profile
&&
profile
->
aws_s3_access_key_id
&&
aws_s3_is_s3_url
(
url
))
{
char
date
[
256
];
char
header
[
1024
];
char
*
authenticate
;
/* Date: */
switch_rfc822_date
(
date
,
switch_time_now
());
snprintf
(
header
,
1024
,
"Date: %s"
,
date
);
headers
=
switch_curl_slist_append
(
headers
,
header
);
/* Authorization: */
authenticate
=
aws_s3_authentication_create
(
verb
,
url
,
content_type
,
""
,
profile
->
aws_s3_access_key_id
,
profile
->
aws_s3_secret_access_key
,
date
);
snprintf
(
header
,
1024
,
"Authorization: %s"
,
authenticate
);
free
(
authenticate
);
headers
=
switch_curl_slist_append
(
headers
,
header
);
}
return
headers
;
}
/**
* Fetch a file via HTTP
* @param cache the cache
* @param profile the HTTP profile
* @param url The cached URL entry
* @param session the (optional) session
* @return SWITCH_STATUS_SUCCESS if successful
*/
static
switch_status_t
http_get
(
url_cache_t
*
cache
,
cached_url_t
*
url
,
switch_core_session_t
*
session
)
static
switch_status_t
http_get
(
url_cache_t
*
cache
,
http_profile_t
*
profile
,
cached_url_t
*
url
,
switch_core_session_t
*
session
)
{
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
switch_curl_slist_t
*
headers
=
NULL
;
/* optional linked-list of HTTP headers */
switch_CURL
*
curl_handle
=
NULL
;
http_get_data_t
get_data
=
{
0
};
long
httpRes
=
0
;
...
...
@@ -778,12 +859,18 @@ static switch_status_t http_get(url_cache_t *cache, cached_url_t *url, switch_co
get_data
.
fd
=
0
;
get_data
.
url
=
url
;
/* add optional AWS S3 headers if necessary */
headers
=
append_aws_s3_headers
(
headers
,
profile
,
"GET"
,
""
,
url
->
url
);
curl_handle
=
switch_curl_easy_init
();
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_DEBUG
,
"opening %s for URL cache
\n
"
,
get_data
.
url
->
filename
);
if
((
get_data
.
fd
=
open
(
get_data
.
url
->
filename
,
O_CREAT
|
O_RDWR
|
O_TRUNC
,
S_IRUSR
|
S_IWUSR
))
>
-
1
)
{
switch_curl_easy_setopt
(
curl_handle
,
CURLOPT_FOLLOWLOCATION
,
1
);
switch_curl_easy_setopt
(
curl_handle
,
CURLOPT_MAXREDIRS
,
10
);
switch_curl_easy_setopt
(
curl_handle
,
CURLOPT_NOSIGNAL
,
1
);
if
(
headers
)
{
switch_curl_easy_setopt
(
curl_handle
,
CURLOPT_HTTPHEADER
,
headers
);
}
switch_curl_easy_setopt
(
curl_handle
,
CURLOPT_URL
,
get_data
.
url
->
url
);
switch_curl_easy_setopt
(
curl_handle
,
CURLOPT_WRITEFUNCTION
,
get_file_callback
);
switch_curl_easy_setopt
(
curl_handle
,
CURLOPT_WRITEDATA
,
(
void
*
)
&
get_data
);
...
...
@@ -808,7 +895,8 @@ static switch_status_t http_get(url_cache_t *cache, cached_url_t *url, switch_co
close
(
get_data
.
fd
);
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_ERROR
,
"open() error: %s
\n
"
,
strerror
(
errno
));
return
SWITCH_STATUS_GENERR
;
status
=
SWITCH_STATUS_GENERR
;
goto
done
;
}
if
(
httpRes
==
200
)
{
...
...
@@ -821,7 +909,14 @@ static switch_status_t http_get(url_cache_t *cache, cached_url_t *url, switch_co
}
else
{
url
->
size
=
0
;
// nothing downloaded or download interrupted
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_ERROR
,
"Received HTTP error %ld trying to fetch %s
\n
"
,
httpRes
,
url
->
url
);
return
SWITCH_STATUS_GENERR
;
status
=
SWITCH_STATUS_GENERR
;
goto
done
;
}
done:
if
(
headers
)
{
switch_curl_slist_free_all
(
headers
);
}
return
status
;
...
...
@@ -858,18 +953,13 @@ static void setup_dir(url_cache_t *cache)
}
}
static
int
isUrl
(
const
char
*
filename
)
{
return
!
zstr
(
filename
)
&&
(
!
strncmp
(
"http://"
,
filename
,
strlen
(
"http://"
))
||
!
strncmp
(
"https://"
,
filename
,
strlen
(
"https://"
)));
}
#define HTTP_PREFETCH_SYNTAX "<url>"
#define HTTP_PREFETCH_SYNTAX "{param=val}<url>"
SWITCH_STANDARD_API
(
http_cache_prefetch
)
{
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
char
*
url
;
if
(
!
isUrl
(
cmd
))
{
if
(
zstr
(
cmd
))
{
stream
->
write_function
(
stream
,
"USAGE: %s
\n
"
,
HTTP_PREFETCH_SYNTAX
);
return
SWITCH_STATUS_SUCCESS
;
}
...
...
@@ -887,7 +977,7 @@ SWITCH_STANDARD_API(http_cache_prefetch)
return
status
;
}
#define HTTP_GET_SYNTAX "<url>"
#define HTTP_GET_SYNTAX "
{param=val}
<url>"
/**
* Get a file from the cache, download if it isn't cached
*/
...
...
@@ -896,9 +986,12 @@ SWITCH_STANDARD_API(http_cache_get)
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
switch_memory_pool_t
*
lpool
=
NULL
;
switch_memory_pool_t
*
pool
=
NULL
;
http_profile_t
*
profile
=
NULL
;
char
*
filename
;
switch_event_t
*
params
=
NULL
;
char
*
url
;
if
(
!
isUrl
(
cmd
))
{
if
(
zstr
(
cmd
))
{
stream
->
write_function
(
stream
,
"USAGE: %s
\n
"
,
HTTP_GET_SYNTAX
);
return
SWITCH_STATUS_SUCCESS
;
}
...
...
@@ -910,7 +1003,16 @@ SWITCH_STANDARD_API(http_cache_get)
pool
=
lpool
;
}
filename
=
url_cache_get
(
&
gcache
,
session
,
cmd
,
1
,
pool
);
/* parse params and get profile */
url
=
switch_core_strdup
(
pool
,
cmd
);
if
(
*
url
==
'{'
)
{
switch_event_create_brackets
(
url
,
'{'
,
'}'
,
','
,
&
params
,
&
url
,
SWITCH_FALSE
);
}
if
(
params
)
{
profile
=
url_cache_http_profile_find
(
&
gcache
,
switch_event_get_header
(
params
,
"profile"
));
}
filename
=
url_cache_get
(
&
gcache
,
profile
,
session
,
url
,
1
,
pool
);
if
(
filename
)
{
stream
->
write_function
(
stream
,
"%s"
,
filename
);
...
...
@@ -923,10 +1025,14 @@ SWITCH_STANDARD_API(http_cache_get)
switch_core_destroy_memory_pool
(
&
lpool
);
}
if
(
params
)
{
switch_event_destroy
(
&
params
);
}
return
status
;
}
#define HTTP_TRYGET_SYNTAX "<url>"
#define HTTP_TRYGET_SYNTAX "
{param=val}
<url>"
/**
* Get a file from the cache, fail if download is needed
*/
...
...
@@ -935,9 +1041,12 @@ SWITCH_STANDARD_API(http_cache_tryget)
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
switch_memory_pool_t
*
lpool
=
NULL
;
switch_memory_pool_t
*
pool
=
NULL
;
http_profile_t
*
profile
=
NULL
;
char
*
filename
;
switch_event_t
*
params
=
NULL
;
char
*
url
;
if
(
!
isUrl
(
cmd
))
{
if
(
zstr
(
cmd
))
{
stream
->
write_function
(
stream
,
"USAGE: %s
\n
"
,
HTTP_GET_SYNTAX
);
return
SWITCH_STATUS_SUCCESS
;
}
...
...
@@ -949,7 +1058,16 @@ SWITCH_STANDARD_API(http_cache_tryget)
pool
=
lpool
;
}
filename
=
url_cache_get
(
&
gcache
,
session
,
cmd
,
0
,
pool
);
/* parse params and get profile */
url
=
switch_core_strdup
(
pool
,
cmd
);
if
(
*
url
==
'{'
)
{
switch_event_create_brackets
(
url
,
'{'
,
'}'
,
','
,
&
params
,
&
url
,
SWITCH_FALSE
);
}
if
(
params
)
{
profile
=
url_cache_http_profile_find
(
&
gcache
,
switch_event_get_header
(
params
,
"profile"
));
}
filename
=
url_cache_get
(
&
gcache
,
profile
,
session
,
url
,
0
,
pool
);
if
(
filename
)
{
if
(
!
strcmp
(
DOWNLOAD_NEEDED
,
filename
))
{
stream
->
write_function
(
stream
,
"-ERR %s
\n
"
,
DOWNLOAD_NEEDED
);
...
...
@@ -965,21 +1083,37 @@ SWITCH_STANDARD_API(http_cache_tryget)
switch_core_destroy_memory_pool
(
&
lpool
);
}
if
(
params
)
{
switch_event_destroy
(
&
params
);
}
return
status
;
}
#define HTTP_PUT_SYNTAX "<url> <file>"
#define HTTP_PUT_SYNTAX "
{param=val}
<url> <file>"
/**
* Put a file to the server
*/
SWITCH_STANDARD_API
(
http_cache_put
)
{
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
http_profile_t
*
profile
=
NULL
;
switch_memory_pool_t
*
lpool
=
NULL
;
switch_memory_pool_t
*
pool
=
NULL
;
char
*
args
=
NULL
;
char
*
argv
[
10
]
=
{
0
};
int
argc
=
0
;
switch_event_t
*
params
=
NULL
;
char
*
url
;
if
(
zstr
(
cmd
)
||
(
strncmp
(
"http://"
,
cmd
,
strlen
(
"http://"
))
&&
strncmp
(
"https://"
,
cmd
,
strlen
(
"https://"
))))
{
if
(
session
)
{
pool
=
switch_core_session_get_pool
(
session
);
}
else
{
switch_core_new_memory_pool
(
&
lpool
);
pool
=
lpool
;
}
if
(
zstr
(
cmd
))
{
stream
->
write_function
(
stream
,
"USAGE: %s
\n
"
,
HTTP_PUT_SYNTAX
);
status
=
SWITCH_STATUS_SUCCESS
;
goto
done
;
...
...
@@ -993,7 +1127,16 @@ SWITCH_STANDARD_API(http_cache_put)
goto
done
;
}
status
=
http_put
(
&
gcache
,
session
,
argv
[
0
],
argv
[
1
]);
/* parse params and get profile */
url
=
switch_core_strdup
(
pool
,
argv
[
0
]);
if
(
*
url
==
'{'
)
{
switch_event_create_brackets
(
url
,
'{'
,
'}'
,
','
,
&
params
,
&
url
,
SWITCH_FALSE
);
}
if
(
params
)
{
profile
=
url_cache_http_profile_find
(
&
gcache
,
switch_event_get_header
(
params
,
"profile"
));
}
status
=
http_put
(
&
gcache
,
profile
,
session
,
url
,
argv
[
1
]);
if
(
status
==
SWITCH_STATUS_SUCCESS
)
{
stream
->
write_function
(
stream
,
"+OK
\n
"
);
}
else
{
...
...
@@ -1002,6 +1145,15 @@ SWITCH_STANDARD_API(http_cache_put)
done
:
switch_safe_free
(
args
);
if
(
lpool
)
{
switch_core_destroy_memory_pool
(
&
lpool
);
}
if
(
params
)
{
switch_event_destroy
(
&
params
);
}
return
status
;
}
...
...
@@ -1066,7 +1218,7 @@ static void *SWITCH_THREAD_FUNC prefetch_thread(switch_thread_t *thread, void *o
static
switch_status_t
do_config
(
url_cache_t
*
cache
)
{
char
*
cf
=
"http_cache.conf"
;
switch_xml_t
cfg
,
xml
,
param
,
settings
;
switch_xml_t
cfg
,
xml
,
param
,
settings
,
profiles
;
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
int
max_urls
;
switch_time_t
default_max_age_sec
;
...
...
@@ -1128,6 +1280,39 @@ static switch_status_t do_config(url_cache_t *cache)
}
}
/* get profiles */
profiles
=
switch_xml_child
(
cfg
,
"profiles"
);
if
(
profiles
)
{
switch_xml_t
profile
;
for
(
profile
=
switch_xml_child
(
profiles
,
"profile"
);
profile
;
profile
=
profile
->
next
)
{
const
char
*
name
=
switch_xml_attr_soft
(
profile
,
"name"
);
if
(
!
zstr
(
name
))
{
switch_xml_t
s3
=
switch_xml_child
(
profile
,
"aws-s3"
);
const
char
*
access_key_id
=
NULL
;
const
char
*
secret_access_key
=
NULL
;
if
(
s3
)
{
switch_xml_t
id
=
switch_xml_child
(
s3
,
"access-key-id"
);
switch_xml_t
secret
=
switch_xml_child
(
s3
,
"secret-access-key"
);
if
(
id
&&
secret
)
{
access_key_id
=
switch_xml_txt
(
id
);
secret_access_key
=
switch_xml_txt
(
secret
);
if
(
!
access_key_id
||
!
secret_access_key
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Missing aws s3 credentials for profile
\"
%s
\"\n
"
,
name
);
access_key_id
=
NULL
;
secret_access_key
=
NULL
;
}
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_INFO
,
"Missing key id or secret
\n
"
);
}
}
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_INFO
,
"Adding profile
\"
%s
\"
to cache
\n
"
,
name
);
url_cache_http_profile_add
(
cache
,
name
,
access_key_id
,
secret_access_key
);
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"HTTP profile missing name
\n
"
);
}
}
}
/* check config */
if
(
max_urls
<=
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"max-urls must be > 0
\n
"
);
...
...
@@ -1179,6 +1364,7 @@ struct http_context {
static
switch_status_t
http_cache_file_open
(
switch_file_handle_t
*
handle
,
const
char
*
path
)
{
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
http_profile_t
*
profile
=
NULL
;
struct
http_context
*
context
=
switch_core_alloc
(
handle
->
memory_pool
,
sizeof
(
*
context
));
const
char
*
local_path
;
...
...
@@ -1187,7 +1373,10 @@ static switch_status_t http_cache_file_open(switch_file_handle_t *handle, const
return
SWITCH_STATUS_FALSE
;
}
local_path
=
url_cache_get
(
&
gcache
,
NULL
,
path
,
1
,
handle
->
memory_pool
);
if
(
handle
->
params
)
{
profile
=
url_cache_http_profile_find
(
&
gcache
,
switch_event_get_header
(
handle
->
params
,
"profile"
));
}
local_path
=
url_cache_get
(
&
gcache
,
profile
,
NULL
,
path
,
1
,
handle
->
memory_pool
);
if
(
!
local_path
)
{
return
SWITCH_STATUS_FALSE
;
}
...
...
@@ -1289,6 +1478,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_http_cache_load)
memset
(
&
gcache
,
0
,
sizeof
(
url_cache_t
));
gcache
.
pool
=
pool
;
switch_core_hash_init
(
&
gcache
.
map
,
gcache
.
pool
);
switch_core_hash_init
(
&
gcache
.
profiles
,
gcache
.
pool
);
switch_mutex_init
(
&
gcache
.
mutex
,
SWITCH_MUTEX_UNNESTED
,
gcache
.
pool
);
switch_thread_rwlock_create
(
&
gcache
.
shutdown_lock
,
gcache
.
pool
);
if
(
do_config
(
&
gcache
)
!=
SWITCH_STATUS_SUCCESS
)
{
return
SWITCH_STATUS_TERM
;
...
...
@@ -1317,11 +1510,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_http_cache_load)
file_interface
->
file_read
=
http_file_read
;
}
switch_core_hash_init
(
&
gcache
.
map
,
gcache
.
pool
);
switch_mutex_init
(
&
gcache
.
mutex
,
SWITCH_MUTEX_UNNESTED
,
gcache
.
pool
);
switch_thread_rwlock_create
(
&
gcache
.
shutdown_lock
,
gcache
.
pool
);
/* create the queue */
/* create the queue from configuration */
gcache
.
queue
.
max_size
=
gcache
.
max_url
;
gcache
.
queue
.
data
=
switch_core_alloc
(
gcache
.
pool
,
sizeof
(
void
*
)
*
gcache
.
queue
.
max_size
);
gcache
.
queue
.
pos
=
0
;
...
...
src/mod/applications/mod_http_cache/test_aws/Makefile
0 → 100644
浏览文件 @
8c8b2176
BASE
=
../../../../..
LOCAL_CFLAGS
+=
-I
../
-I
./
LOCAL_OBJS
=
main.o ../aws.o
LOCAL_SOURCES
=
main.c
include
$(BASE)/build/modmake.rules
local_all
:
libtool
--mode
=
link
gcc main.o ../aws.o
-o
test
test_aws.la
local_clean
:
-
rm test
src/mod/applications/mod_http_cache/test_aws/main.c
0 → 100644
浏览文件 @
8c8b2176
#include <switch.h>
#include "test.h"
#include "aws.h"
/**
* Test string to sign generation
*/
static
void
test_string_to_sign
(
void
)
{
ASSERT_STRING_EQUALS
(
"GET
\n\n\n
Fri, 17 May 2013 19:35:26 GMT
\n
/rienzo-vault/troporocks.mp3"
,
aws_s3_string_to_sign
(
"GET"
,
"rienzo-vault"
,
"troporocks.mp3"
,
""
,
""
,
"Fri, 17 May 2013 19:35:26 GMT"
));
ASSERT_STRING_EQUALS
(
"GET
\n
c8fdb181845a4ca6b8fec737b3581d76
\n
audio/mpeg
\n
Thu, 17 Nov 2005 18:49:58 GMT
\n
/foo/man.chu"
,
aws_s3_string_to_sign
(
"GET"
,
"foo"
,
"man.chu"
,
"audio/mpeg"
,
"c8fdb181845a4ca6b8fec737b3581d76"
,
"Thu, 17 Nov 2005 18:49:58 GMT"
));
ASSERT_STRING_EQUALS
(
"
\n\n\n\n
//"
,
aws_s3_string_to_sign
(
""
,
""
,
""
,
""
,
""
,
""
));
ASSERT_STRING_EQUALS
(
"
\n\n\n\n
//"
,
aws_s3_string_to_sign
(
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
));
}
/**
* Test signature generation
*/
static
void
test_signature
(
void
)
{
char
signature
[
S3_SIGNATURE_LENGTH_MAX
];
signature
[
0
]
=
'\0'
;
ASSERT_STRING_EQUALS
(
"weGrLrc9HDlkYPTepVl0A9VYNlw="
,
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
"GET
\n\n\n
Fri, 17 May 2013 19:35:26 GMT
\n
/rienzo-vault/troporocks.mp3"
,
"hOIZt1oeTX1JzINOMBoKf0BxONRZNQT1J8gIznLx"
));
ASSERT_STRING_EQUALS
(
"jZNOcbfWmD/A/f3hSvVzXZjM2HU="
,
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
"PUT
\n
c8fdb181845a4ca6b8fec737b3581d76
\n
text/html
\n
Thu, 17 Nov 2005 18:49:58 GMT
\n
x-amz-magic:abracadabra
\n
x-amz-meta-author:foo@bar.com
\n
/quotes/nelson"
,
"OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV"
));
ASSERT_STRING_EQUALS
(
"5m+HAmc5JsrgyDelh9+a2dNrzN8="
,
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
"GET
\n\n\n\n
x-amz-date:Thu, 17 Nov 2005 18:49:58 GMT
\n
x-amz-magic:abracadabra
\n
/quotes/nelson"
,
"OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV"
));
ASSERT_STRING_EQUALS
(
"OKA87rVp3c4kd59t8D3diFmTfuo="
,
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
""
,
"OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV"
));
ASSERT_STRING_EQUALS
(
"OKA87rVp3c4kd59t8D3diFmTfuo="
,
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
NULL
,
"OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV"
));
ASSERT_NULL
(
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
"GET
\n\n\n\n
x-amz-date:Thu, 17 Nov 2005 18:49:58 GMT
\n
x-amz-magic:abracadabra
\n
/quotes/nelson"
,
""
));
ASSERT_NULL
(
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
""
,
""
));
ASSERT_NULL
(
aws_s3_signature
(
signature
,
S3_SIGNATURE_LENGTH_MAX
,
NULL
,
NULL
));
ASSERT_NULL
(
aws_s3_signature
(
NULL
,
S3_SIGNATURE_LENGTH_MAX
,
"PUT
\n
c8fdb181845a4ca6b8fec737b3581d76
\n
text/html
\n
Thu, 17 Nov 2005 18:49:58 GMT
\n
x-amz-magic:abracadabra
\n
x-amz-meta-author:foo@bar.com
\n
/quotes/nelson"
,
"OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV"
));
ASSERT_NULL
(
aws_s3_signature
(
signature
,
0
,
"PUT
\n
c8fdb181845a4ca6b8fec737b3581d76
\n
text/html
\n
Thu, 17 Nov 2005 18:49:58 GMT
\n
x-amz-magic:abracadabra
\n
x-amz-meta-author:foo@bar.com
\n
/quotes/nelson"
,
"OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV"
));
/* TODO freeswitch bug... */
//ASSERT_STRING_EQUALS("jZNO", aws_s3_signature(signature, 5, "PUT\nc8fdb181845a4ca6b8fec737b3581d76\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-amz-magic:abracadabra\nx-amz-meta-author:foo@bar.com\n/quotes/nelson", "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV"));
}
/**
* Test amazon URL detection
*/
static
void
test_check_url
(
void
)
{
ASSERT_TRUE
(
aws_s3_is_s3_url
(
"http://bucket.s3.amazonaws.com/object.ext"
));
ASSERT_TRUE
(
aws_s3_is_s3_url
(
"http://bucket.s3.amazonaws.com/object"
));
ASSERT_TRUE
(
aws_s3_is_s3_url
(
"http://red.bucket.s3.amazonaws.com/object.ext"
));
ASSERT_TRUE
(
aws_s3_is_s3_url
(
"https://bucket.s3.amazonaws.com/object.ext"
));
ASSERT_TRUE
(
aws_s3_is_s3_url
(
"https://bucket.s3.amazonaws.com/object"
));
ASSERT_FALSE
(
aws_s3_is_s3_url
(
"bucket.s3.amazonaws.com/object.ext"
));
ASSERT_FALSE
(
aws_s3_is_s3_url
(
"https://s3.amazonaws.com/bucket/object"
));
ASSERT_FALSE
(
aws_s3_is_s3_url
(
"http://s3.amazonaws.com/bucket/object"
));
ASSERT_FALSE
(
aws_s3_is_s3_url
(
"http://google.com/"
));
ASSERT_FALSE
(
aws_s3_is_s3_url
(
"http://phono.com/audio/troporocks.mp3"
));
ASSERT_FALSE
(
aws_s3_is_s3_url
(
""
));
ASSERT_FALSE
(
aws_s3_is_s3_url
(
NULL
));
}
/**
* Test bucket/object extraction from URL
*/
static
void
test_parse_url
(
void
)
{
char
*
bucket
;
char
*
object
;
aws_s3_parse_url
(
strdup
(
"http://quotes.s3.amazonaws.com/nelson"
),
&
bucket
,
&
object
);
ASSERT_STRING_EQUALS
(
"quotes"
,
bucket
);
ASSERT_STRING_EQUALS
(
"nelson"
,
object
);
aws_s3_parse_url
(
strdup
(
"https://quotes.s3.amazonaws.com/nelson.mp3"
),
&
bucket
,
&
object
);
ASSERT_STRING_EQUALS
(
"quotes"
,
bucket
);
ASSERT_STRING_EQUALS
(
"nelson.mp3"
,
object
);
aws_s3_parse_url
(
strdup
(
"http://s3.amazonaws.com/quotes/nelson"
),
&
bucket
,
&
object
);
ASSERT_NULL
(
bucket
);
ASSERT_NULL
(
object
);
aws_s3_parse_url
(
strdup
(
"http://quotes/quotes/nelson"
),
&
bucket
,
&
object
);
ASSERT_NULL
(
bucket
);
ASSERT_NULL
(
object
);
aws_s3_parse_url
(
strdup
(
"http://quotes.s3.amazonaws.com/"
),
&
bucket
,
&
object
);
ASSERT_NULL
(
bucket
);
ASSERT_NULL
(
object
);
aws_s3_parse_url
(
strdup
(
"http://quotes.s3.amazonaws.com"
),
&
bucket
,
&
object
);
ASSERT_NULL
(
bucket
);
ASSERT_NULL
(
object
);
aws_s3_parse_url
(
strdup
(
"http://quotes"
),
&
bucket
,
&
object
);
ASSERT_NULL
(
bucket
);
ASSERT_NULL
(
object
);
aws_s3_parse_url
(
strdup
(
""
),
&
bucket
,
&
object
);
ASSERT_NULL
(
bucket
);
ASSERT_NULL
(
object
);
aws_s3_parse_url
(
NULL
,
&
bucket
,
&
object
);
ASSERT_NULL
(
bucket
);
ASSERT_NULL
(
object
);
}
/**
* Test Authorization header creation
*/
static
void
test_authorization_header
(
void
)
{
ASSERT_STRING_EQUALS
(
"AWS AKIAIOSFODNN7EXAMPLE:YJkomOaqUJlvEluDq4fpusID38Y="
,
aws_s3_authentication_create
(
"GET"
,
"https://vault.s3.amazonaws.com/awesome.mp3"
,
"audio/mpeg"
,
""
,
"AKIAIOSFODNN7EXAMPLE"
,
"0123456789012345678901234567890123456789"
,
"1234567890"
));
}
/**
* Test pre-signed URL creation
*/
static
void
test_presigned_url
(
void
)
{
ASSERT_STRING_EQUALS
(
"https://vault.s3.amazonaws.com/awesome.mp3?Signature=YJkomOaqUJlvEluDq4fpusID38Y%3D&Expires=1234567890&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE"
,
aws_s3_presigned_url_create
(
"GET"
,
"https://vault.s3.amazonaws.com/awesome.mp3"
,
"audio/mpeg"
,
""
,
"AKIAIOSFODNN7EXAMPLE"
,
"0123456789012345678901234567890123456789"
,
"1234567890"
));
}
/**
* main program
*/
int
main
(
int
argc
,
char
**
argv
)
{
TEST_INIT
TEST
(
test_string_to_sign
);
TEST
(
test_signature
);
TEST
(
test_check_url
);
TEST
(
test_parse_url
);
TEST
(
test_authorization_header
);
TEST
(
test_presigned_url
);
return
0
;
}
src/mod/applications/mod_http_cache/test_aws/test.h
0 → 100644
浏览文件 @
8c8b2176
/*
* test.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2013, Grasshopper
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is test.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is Grasshopper
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Rienzo <chris.rienzo@grasshopper.com>
*
* test.h -- simple unit testing macros
*
*/
#ifndef TEST_H
#define TEST_H
#define assert_equals(test, expected_str, expected, actual, file, line) \
{ \
int actual_val = actual; \
if (expected != actual_val) { \
printf("TEST\t%s\tFAIL\t%s\t%i\t!=\t%i\t%s:%i\n", test, expected_str, expected, actual_val, file, line); \
exit(1); \
} else { \
printf("TEST\t%s\tPASS\n", test); \
} \
}
#define assert_string_equals(test, expected, actual, file, line) \
{ \
const char *actual_str = actual; \
if (!actual_str || strcmp(expected, actual_str)) { \
printf("TEST\t%s\tFAIL\t\t%s\t!=\t%s\t%s:%i\n", test, expected, actual_str, file, line); \
exit(1); \
} else { \
printf("TEST\t%s\tPASS\n", test); \
} \
}
#define assert_not_null(test, actual, file, line) \
{ \
const void *actual_val = actual; \
if (!actual_val) { \
printf("TEST\t%s\tFAIL\t\t\t\t\t%s:%i\n", test, file, line); \
exit(1); \
} else { \
printf("TEST\t%s\tPASS\n", test); \
} \
}
#define assert_null(test, actual, file, line) \
{ \
const void *actual_val = actual; \
if (actual_val) { \
printf("TEST\t%s\tFAIL\t\t\t\t\t%s:%i\n", test, file, line); \
exit(1); \
} else { \
printf("TEST\t%s\tPASS\n", test); \
} \
}
#define assert_true(test, actual, file, line) \
{ \
int actual_val = actual; \
if (!actual_val) { \
printf("TEST\t%s\tFAIL\t\t\t\t\t%s:%i\n", test, file, line); \
exit(1); \
} else { \
printf("TEST\t%s\tPASS\n", test); \
} \
}
#define assert_false(test, actual, file, line) \
{ \
int actual_val = actual; \
if (actual_val) { \
printf("TEST\t%s\tFAIL\t\t\t\t\t%s:%i\n", test, file, line); \
exit(1); \
} else { \
printf("TEST\t%s\tPASS\n", test); \
} \
}
#define ASSERT_EQUALS(expected, actual) assert_equals(#actual, #expected, expected, actual, __FILE__, __LINE__)
#define ASSERT_STRING_EQUALS(expected, actual) assert_string_equals(#actual, expected, actual, __FILE__, __LINE__)
#define ASSERT_NOT_NULL(actual) assert_not_null(#actual " not null", actual, __FILE__, __LINE__)
#define ASSERT_NULL(actual) assert_null(#actual " is null", actual, __FILE__, __LINE__)
#define ASSERT_TRUE(actual) assert_true(#actual " is true", actual, __FILE__, __LINE__)
#define ASSERT_FALSE(actual) assert_false(#actual " is false", actual, __FILE__, __LINE__)
#define SKIP_ASSERT_EQUALS(expected, actual) if (0) { ASSERT_EQUALS(expected, actual); }
#define TEST(name) printf("TEST BEGIN\t" #name "\n"); name(); printf("TEST END\t"#name "\tPASS\n");
#define SKIP_TEST(name) if (0) { TEST(name) };
#define TEST_INIT const char *err; switch_core_init(0, SWITCH_TRUE, &err);
#endif
src/mod/applications/mod_http_cache/test_aws/test_aws.c
0 → 100644
浏览文件 @
8c8b2176
int
dummy
(
int
i
)
{
return
0
;
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论