提交 6263f260 authored 作者: Christopher Rienzo's avatar Christopher Rienzo

Merge pull request #941 in FS/freeswitch from…

Merge pull request #941 in FS/freeswitch from ~RICHARD.SCREENE/freeswitch:feature/FS-9457-mod_http_cache-work-with-azure-blob to master

* commit '55978ba0':
  FS-9457 [mod_http_cache] Allow GET and PUT from Azure Blob Service
......@@ -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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论