提交 55978ba0 authored 作者: Richard Screene's avatar Richard Screene

FS-9457 [mod_http_cache] Allow GET and PUT from Azure Blob Service

Only send final PUT on Azure profiles

Fix core dump when reading Azure key from environment variable

Improve interface between mod_http_cache and storage providers

Remove debug

Remove out-of-date TODO

Add new configuration to example

Changes arising from Christopher Rienzo's comments

Add function to pointers to the profile to allow for better integration with the storage providers.

Add function to pointers to the profile to allow for better integration with the storage providers

Remove old header file inclusion
上级 10800169
......@@ -2,7 +2,7 @@ include $(top_srcdir)/build/modmake.rulesam
MODNAME=mod_http_cache
mod_LTLIBRARIES = mod_http_cache.la
mod_http_cache_la_SOURCES = mod_http_cache.c aws.c
mod_http_cache_la_SOURCES = mod_http_cache.c common.c aws.c azure.c
mod_http_cache_la_CFLAGS = $(AM_CFLAGS)
mod_http_cache_la_CPPFLAGS = $(CURL_CFLAGS) $(AM_CPPFLAGS)
mod_http_cache_la_LIBADD = $(switch_builddir)/libfreeswitch.la
......
......@@ -37,26 +37,6 @@
/* 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, const char *base_domain)
{
if (!zstr(base_domain)) {
char *base_domain_escaped;
char regex[1024];
int result;
base_domain_escaped = switch_string_replace(base_domain, ".", "\\.");
switch_snprintf(regex, 1024, "^https?://\\w[-\\w.]{1,61}\\w\\.%s/.*$", base_domain_escaped);
result = !zstr(url) && switch_regex_match(url, regex) == SWITCH_STATUS_SUCCESS;
switch_safe_free(base_domain_escaped);
return result;
}
/* AWS bucket naming rules are complex... this match only supports virtual hosting of buckets */
return !zstr(url) && switch_regex_match(url, "^https?://\\w[-\\w.]{1,61}\\w\\.s3([-\\w]+)?\\.amazonaws\\.com/.*$") == SWITCH_STATUS_SUCCESS;
}
/**
* Create the string to sign for a AWS signature calculation
* @param verb (PUT/GET)
......@@ -115,100 +95,6 @@ char *aws_s3_signature(char *signature, int signature_length, const char *string
return signature;
}
/**
* Reverse string substring search
*/
static char *my_strrstr(const char *haystack, const char *needle)
{
char *s;
size_t needle_len;
size_t haystack_len;
if (zstr(haystack)) {
return NULL;
}
if (zstr(needle)) {
return (char *)haystack;
}
needle_len = strlen(needle);
haystack_len = strlen(haystack);
if (needle_len > haystack_len) {
return NULL;
}
s = (char *)(haystack + haystack_len - needle_len);
do {
if (!strncmp(s, needle, needle_len)) {
return s;
}
} while (s-- != haystack);
return NULL;
}
/**
* Parse bucket and object from URL
* @param url to parse. This value is modified.
* @param base_domain of URL (assumes s3.amazonaws.com if not specified)
* @param bucket to store result in
* @param bucket_length of result buffer
*/
void aws_s3_parse_url(char *url, const char *base_domain, char **bucket, char **object)
{
char *bucket_start = NULL;
char *bucket_end;
char *object_start;
*bucket = NULL;
*object = NULL;
if (!aws_s3_is_s3_url(url, base_domain)) {
return;
}
/* expect: http(s)://bucket.foo-bar.s3.amazonaws.com/object */
if (!strncasecmp(url, "https://", 8)) {
bucket_start = url + 8;
} else if (!strncasecmp(url, "http://", 7)) {
bucket_start = url + 7;
}
if (zstr(bucket_start)) {
/* invalid URL */
return;
}
{
char base_domain_match[1024];
if (zstr(base_domain)) {
base_domain = "s3";
}
switch_snprintf(base_domain_match, 1024, ".%s", base_domain);
bucket_end = my_strrstr(bucket_start, base_domain_match);
}
if (!bucket_end) {
/* invalid URL */
return;
}
*bucket_end = '\0';
object_start = strchr(bucket_end + 1, '/');
if (!object_start) {
/* invalid URL */
return;
}
object_start++;
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)
......@@ -231,7 +117,7 @@ char *aws_s3_presigned_url_create(const char *verb, const char *url, const char
char *object;
/* create URL encoded signature */
aws_s3_parse_url(url_dup, base_domain, &bucket, &object);
parse_url(url_dup, base_domain, "s3", &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);
......@@ -266,7 +152,7 @@ char *aws_s3_authentication_create(const char *verb, const char *url, const char
char *object;
/* create base64 encoded signature */
aws_s3_parse_url(url_dup, base_domain, &bucket, &object);
parse_url(url_dup, base_domain, "s3", &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);
......@@ -276,6 +162,80 @@ char *aws_s3_authentication_create(const char *verb, const char *url, const char
return switch_mprintf("AWS %s:%s", aws_access_key_id, signature);
}
switch_status_t aws_s3_config_profile(switch_xml_t xml, http_profile_t *profile) {
switch_status_t status = SWITCH_STATUS_SUCCESS;
profile->append_headers_ptr = aws_s3_append_headers;
switch_xml_t base_domain_xml = switch_xml_child(xml, "base-domain");
/* check if environment variables set the keys */
profile->aws_s3_access_key_id = getenv("AWS_ACCESS_KEY_ID");
profile->secret_access_key = getenv("AWS_SECRET_ACCESS_KEY");
if (!zstr(profile->aws_s3_access_key_id) && !zstr(profile->secret_access_key)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Using AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables for s3 access on profile \"%s\"\n", profile->name);
profile->aws_s3_access_key_id = strdup(profile->aws_s3_access_key_id);
profile->secret_access_key = strdup(profile->secret_access_key);
} else {
/* use configuration for keys */
switch_xml_t id = switch_xml_child(xml, "access-key-id");
switch_xml_t secret = switch_xml_child(xml, "secret-access-key");
if (id && secret) {
profile->aws_s3_access_key_id = switch_strip_whitespace(switch_xml_txt(id));
profile->secret_access_key = switch_strip_whitespace(switch_xml_txt(secret));
if (zstr(profile->aws_s3_access_key_id) || zstr(profile->secret_access_key)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing Azure Blob credentials for profile \"%s\"\n", profile->name);
switch_safe_free(profile->aws_s3_access_key_id);
profile->aws_s3_access_key_id = NULL;
switch_safe_free(profile->secret_access_key);
profile->secret_access_key = NULL;
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing key id or secret\n");
status = SWITCH_STATUS_FALSE;
}
}
if (base_domain_xml) {
profile->base_domain = switch_strip_whitespace(switch_xml_txt(base_domain_xml));
if (zstr(profile->base_domain)) {
switch_safe_free(profile->base_domain);
profile->base_domain = NULL;
}
}
return status;
}
/**
* 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
*/
switch_curl_slist_t *aws_s3_append_headers(http_profile_t *profile, switch_curl_slist_t *headers,
const char *verb, unsigned int content_length, const char *content_type, const char *url, const unsigned int block_num, char **query_string)
{
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, profile->base_domain, content_type, "", profile->aws_s3_access_key_id, profile->secret_access_key, date);
snprintf(header, 1024, "Authorization: %s", authenticate);
free(authenticate);
headers = switch_curl_slist_append(headers, header);
return headers;
}
/* For Emacs:
* Local Variables:
* mode:c
......
......@@ -30,17 +30,24 @@
#define AWS_H
#include <switch.h>
#include <switch_curl.h>
#include "common.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, const char *base_domain);
void aws_s3_parse_url(char *url, const char *base_domain, char **bucket, char **object);
switch_curl_slist_t *aws_s3_append_headers(http_profile_t *profile, switch_curl_slist_t *headers,
const char *verb, unsigned int content_length, const char *content_type, const char *url, const unsigned int block_num, char **query_string);
switch_status_t aws_s3_config_profile(switch_xml_t xml, http_profile_t *profile);
// the following functions are exposed only so that the unit tests still work
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);
void aws_s3_parse_url(char *url, const char *base_domain, char **bucket, char **object);
char *aws_s3_presigned_url_create(const char *verb, const char *url, const char *base_domain, 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 *base_domain, 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:
......
差异被折叠。
/*
* azure.h for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2013-2014, 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>
* Richard Screene <richard.screene@thisisdrum.com>
*
* azure.h - Some Azure Blob Service helper functions
*
*/
#ifndef AZURE_H
#define AZURE_H
#include <switch.h>
#include <switch_curl.h>
#include "common.h"
#define AZURE_SIGNATURE_LENGTH_MAX 256
switch_curl_slist_t *azure_blob_append_headers(http_profile_t *profile, switch_curl_slist_t *headers,
const char *verb, unsigned int content_length, const char *content_type, const char *url, const unsigned int block_num, char **query_string);
switch_status_t azure_blob_finalise_put(http_profile_t *profile, const char *url, const unsigned int num_blocks);
switch_status_t azure_blob_config_profile(switch_xml_t xml, http_profile_t *profile);
#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 noet
*/
/*
* common.c for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2013-2014, 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 common.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>
*
* common.c - Functions common to the store provider
*
*/
#include <switch.h>
/**
* Reverse string substring search
*/
static char *my_strrstr(const char *haystack, const char *needle)
{
char *s;
size_t needle_len;
size_t haystack_len;
if (zstr(haystack)) {
return NULL;
}
if (zstr(needle)) {
return (char *)haystack;
}
needle_len = strlen(needle);
haystack_len = strlen(haystack);
if (needle_len > haystack_len) {
return NULL;
}
s = (char *)(haystack + haystack_len - needle_len);
do {
if (!strncmp(s, needle, needle_len)) {
return s;
}
} while (s-- != haystack);
return NULL;
}
void parse_url(char *url, const char *base_domain, const char *default_base_domain, char **bucket, char **object)
{
char *bucket_start = NULL;
char *bucket_end;
char *object_start;
*bucket = NULL;
*object = NULL;
if (zstr(url)) {
return;
}
/* expect: http(s)://bucket.foo-bar.s3.amazonaws.com/object */
if (!strncasecmp(url, "https://", 8)) {
bucket_start = url + 8;
} else if (!strncasecmp(url, "http://", 7)) {
bucket_start = url + 7;
}
if (zstr(bucket_start)) {
/* invalid URL */
return;
}
{
char base_domain_match[1024];
if (zstr(base_domain)) {
base_domain = default_base_domain;
}
switch_snprintf(base_domain_match, 1024, ".%s", base_domain);
bucket_end = my_strrstr(bucket_start, base_domain_match);
}
if (!bucket_end) {
/* invalid URL */
return;
}
*bucket_end = '\0';
object_start = strchr(bucket_end + 1, '/');
if (!object_start) {
/* invalid URL */
return;
}
object_start++;
if (zstr(bucket_start) || zstr(object_start)) {
/* invalid URL */
return;
}
// ignore the query string from the end of the URL
char *p = strchr(object_start, '&');
if (p) {
*p = '\0';
}
*bucket = bucket_start;
*object = object_start;
}
/* 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 noet
*/
#ifndef COMMON_H
#define COMMON_H
#include <switch.h>
/**
* An http profile. Defines optional credentials
* for access to Amazon S3 and Azure Blob Service
*/
struct http_profile {
const char *name;
char *aws_s3_access_key_id;
char *secret_access_key;
char *base_domain;
switch_size_t bytes_per_block;
// function to be called to add the profile specific headers to the GET/PUT requests
switch_curl_slist_t *(*append_headers_ptr)(struct http_profile *profile, switch_curl_slist_t *headers,
const char *verb, unsigned int content_length, const char *content_type, const char *url, const unsigned int block_num, char **query_string);
// function to be called to perform the profile-specific actions at the end of the PUT operation
switch_status_t (*finalise_put_ptr)(struct http_profile *profile, const char *url, const unsigned int num_blocks);
};
typedef struct http_profile http_profile_t;
void parse_url(char *url, const char *base_domain, const char *default_base_domain, char **bucket, char **object);
#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 noet
*/
......@@ -30,6 +30,17 @@
<domain name="bucket2.s3.amazonaws.com"/>
</domains>
</profile>
<profile name="blob">
<azure-blob>
<!-- key identifier, can override with AZURE_STORAGE_ACCESS_KEY environment variable -->
<secret-access-key>kOOY4Y/sqZU9bsLjmN+9McVwTry+UIn1Owt4Zs/2S2FQT0eAWLKsk
Z0V6/gGFqCAKVvwXoGjqUn7PNbVjhZiNA==</secret-access-key>
</azure-blob>
<domains>
<domain name="account.blob.core.windows.net"/>
</domains>
</profile>
</profiles>
</configuration>
......
BASE=../../../../..
LOCAL_CFLAGS += -I../ -I./
LOCAL_OBJS= main.o ../aws.o
LOCAL_OBJS= main.o ../aws.o ../common.o
LOCAL_SOURCES= main.c
include $(BASE)/build/modmake.rules
......
......@@ -36,35 +36,6 @@ static void test_signature(void)
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-us-west-1.amazonaws.com/object.ext", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3-us-west-1.amazonaws.com/object.ext", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object.ext", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.s3.amazonaws.com/object", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("http://red.bucket.s3.amazonaws.com/object.ext", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object.ext", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/object", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/recordings/1240fwjf8we.mp3", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("https://bucket.s3.amazonaws.com/en/us/8000/1232345.mp3", NULL));
ASSERT_TRUE(aws_s3_is_s3_url("https://bucket_with_underscore.s3.amazonaws.com/en/us/8000/1232345.mp3", NULL));
ASSERT_FALSE(aws_s3_is_s3_url("bucket.s3.amazonaws.com/object.ext", NULL));
ASSERT_FALSE(aws_s3_is_s3_url("https://s3.amazonaws.com/bucket/object", NULL));
ASSERT_FALSE(aws_s3_is_s3_url("http://s3.amazonaws.com/bucket/object", NULL));
ASSERT_FALSE(aws_s3_is_s3_url("http://google.com/", NULL));
ASSERT_FALSE(aws_s3_is_s3_url("http://phono.com/audio/troporocks.mp3", NULL));
ASSERT_FALSE(aws_s3_is_s3_url("", NULL));
ASSERT_FALSE(aws_s3_is_s3_url(NULL, NULL));
ASSERT_FALSE(aws_s3_is_s3_url("https://example.com/bucket/object", "example.com"));
ASSERT_TRUE(aws_s3_is_s3_url("http://bucket.example.com/object", "example.com"));
ASSERT_FALSE(aws_s3_is_s3_url("", "example.com"));
ASSERT_FALSE(aws_s3_is_s3_url(NULL, "example.com"));
}
/**
* Test bucket/object extraction from URL
*/
......@@ -72,55 +43,55 @@ static void test_parse_url(void)
{
char *bucket;
char *object;
aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/nelson"), NULL, &bucket, &object);
parse_url(strdup("http://quotes.s3.amazonaws.com/nelson"), NULL, "s3", &bucket, &object);
ASSERT_STRING_EQUALS("quotes", bucket);
ASSERT_STRING_EQUALS("nelson", object);
aws_s3_parse_url(strdup("https://quotes.s3.amazonaws.com/nelson.mp3"), NULL, &bucket, &object);
parse_url(strdup("https://quotes.s3.amazonaws.com/nelson.mp3"), NULL, "s3", &bucket, &object);
ASSERT_STRING_EQUALS("quotes", bucket);
ASSERT_STRING_EQUALS("nelson.mp3", object);
aws_s3_parse_url(strdup("http://s3.amazonaws.com/quotes/nelson"), NULL, &bucket, &object);
parse_url(strdup("http://s3.amazonaws.com/quotes/nelson"), NULL, "s3", &bucket, &object);
ASSERT_NULL(bucket);
ASSERT_NULL(object);
aws_s3_parse_url(strdup("http://quotes/quotes/nelson"), NULL, &bucket, &object);
parse_url(strdup("http://quotes/quotes/nelson"), NULL, "s3", &bucket, &object);
ASSERT_NULL(bucket);
ASSERT_NULL(object);
aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com/"), NULL, &bucket, &object);
parse_url(strdup("http://quotes.s3.amazonaws.com/"), NULL, "s3", &bucket, &object);
ASSERT_NULL(bucket);
ASSERT_NULL(object);
aws_s3_parse_url(strdup("http://quotes.s3.amazonaws.com"), NULL, &bucket, &object);
parse_url(strdup("http://quotes.s3.amazonaws.com"), NULL, "s3", &bucket, &object);
ASSERT_NULL(bucket);
ASSERT_NULL(object);
aws_s3_parse_url(strdup("http://quotes"), NULL, &bucket, &object);
parse_url(strdup("http://quotes"), NULL, "s3", &bucket, &object);
ASSERT_NULL(bucket);
ASSERT_NULL(object);
aws_s3_parse_url(strdup(""), NULL, &bucket, &object);
parse_url(strdup(""), NULL, "s3", &bucket, &object);
ASSERT_NULL(bucket);
ASSERT_NULL(object);
aws_s3_parse_url(NULL, NULL, &bucket, &object);
parse_url(NULL, NULL, "s3", &bucket, &object);
ASSERT_NULL(bucket);
ASSERT_NULL(object);
aws_s3_parse_url(strdup("http://bucket.s3.amazonaws.com/voicemails/recording.wav"), NULL, &bucket, &object);
parse_url(strdup("http://bucket.s3.amazonaws.com/voicemails/recording.wav"), NULL, "s3", &bucket, &object);
ASSERT_STRING_EQUALS("bucket", bucket);
ASSERT_STRING_EQUALS("voicemails/recording.wav", object);
aws_s3_parse_url(strdup("https://my-bucket-with-dash.s3-us-west-2.amazonaws.com/greeting/file/1002/Lumino.mp3"), NULL, &bucket, &object);
parse_url(strdup("https://my-bucket-with-dash.s3-us-west-2.amazonaws.com/greeting/file/1002/Lumino.mp3"), NULL, "s3", &bucket, &object);
ASSERT_STRING_EQUALS("my-bucket-with-dash", bucket);
ASSERT_STRING_EQUALS("greeting/file/1002/Lumino.mp3", object);
aws_s3_parse_url(strdup("http://quotes.s3.foo.bar.s3.amazonaws.com/greeting/file/1002/Lumino.mp3"), NULL, &bucket, &object);
parse_url(strdup("http://quotes.s3.foo.bar.s3.amazonaws.com/greeting/file/1002/Lumino.mp3"), NULL, "s3", &bucket, &object);
ASSERT_STRING_EQUALS("quotes.s3.foo.bar", bucket);
ASSERT_STRING_EQUALS("greeting/file/1002/Lumino.mp3", object);
aws_s3_parse_url(strdup("http://quotes.s3.foo.bar.example.com/greeting/file/1002/Lumino.mp3"), "example.com", &bucket, &object);
parse_url(strdup("http://quotes.s3.foo.bar.example.com/greeting/file/1002/Lumino.mp3"), "example.com", "s3", &bucket, &object);
ASSERT_STRING_EQUALS("quotes.s3.foo.bar", bucket);
ASSERT_STRING_EQUALS("greeting/file/1002/Lumino.mp3", object);
}
......@@ -153,7 +124,6 @@ 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);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论