├── test ├── data │ └── .ignore ├── test.h.in ├── oss_config.c ├── oss_config.h ├── CMakeLists.txt ├── oss_test_util.h ├── test_all.c ├── oss_test_util.c ├── CuTest.h ├── CuTest-README.txt ├── test_aos.c └── CuTest.c ├── .gitignore ├── sample ├── oss_config.h ├── oss_config.c ├── oss_sample_util.h ├── oss_delete_object_sample.c ├── oss_head_object_sample.c ├── oss_sample_util.c ├── CMakeLists.txt ├── oss_append_object_sample.c ├── oss_put_object_sample.c ├── oss_get_object_sample.c └── oss_multipart_upload_sample.c ├── src ├── aos_fstack.h ├── aos_fstack.c ├── aos_status.h ├── aos_string.c ├── aos_string.h ├── aos_buf.h ├── oss_auth.h ├── oss_define.c ├── aos_util.h ├── aos_http_io.h ├── aos_log.c ├── aos_log.h ├── aos_status.c ├── aos_list.h ├── aos_define.h ├── aos_transport.h ├── oss_xml.h ├── aos_buf.c ├── oss_define.h ├── oss_util.h ├── aos_http_io.c ├── aos_util.c ├── oss_auth.c └── oss_bucket.c ├── CHANGELOG.md ├── .travis.yml ├── README.md └── CMakeLists.txt /test/data/.ignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | clean.sh 4 | -------------------------------------------------------------------------------- /test/test.h.in: -------------------------------------------------------------------------------- 1 | #define TEST_DIR "@PROJECT_SOURCE_DIR@" 2 | -------------------------------------------------------------------------------- /test/oss_config.c: -------------------------------------------------------------------------------- 1 | #include "oss_config.h" 2 | 3 | char* TEST_OSS_ENDPOINT = NULL; 4 | char* TEST_ACCESS_KEY_ID = NULL; 5 | char* TEST_ACCESS_KEY_SECRET = NULL; 6 | char* TEST_BUCKET_NAME = NULL; 7 | -------------------------------------------------------------------------------- /test/oss_config.h: -------------------------------------------------------------------------------- 1 | #ifndef OSS_TEST_CONFIG_H 2 | #define OSS_TEST_CONFIG_H 3 | 4 | #include "oss_define.h" 5 | 6 | OSS_CPP_START 7 | 8 | extern char* TEST_OSS_ENDPOINT; 9 | extern char* TEST_ACCESS_KEY_ID; 10 | extern char* TEST_ACCESS_KEY_SECRET; 11 | extern char* TEST_BUCKET_NAME; 12 | 13 | OSS_CPP_END 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sample/oss_config.h: -------------------------------------------------------------------------------- 1 | #ifndef OSS_TEST_CONFIG_H 2 | #define OSS_TEST_CONFIG_H 3 | 4 | #include "oss_define.h" 5 | 6 | OSS_CPP_START 7 | 8 | extern const char OSS_ENDPOINT[]; 9 | extern const char ACCESS_KEY_ID[]; 10 | extern const char ACCESS_KEY_SECRET[]; 11 | extern const char BUCKET_NAME[]; 12 | extern const char OBJECT_NAME[]; 13 | extern const char DIR_NAME[]; 14 | extern const char MULTIPART_UPLOAD_FILE_PATH[]; 15 | 16 | OSS_CPP_END 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /sample/oss_config.c: -------------------------------------------------------------------------------- 1 | #include "oss_config.h" 2 | 3 | const char OSS_ENDPOINT[] = ""; 4 | const char ACCESS_KEY_ID[] = ""; 5 | const char ACCESS_KEY_SECRET[] = ""; 6 | const char BUCKET_NAME[] = ""; 7 | const char OBJECT_NAME[] = ""; 8 | const char MULTIPART_UPLOAD_FILE_PATH[] = ""; 9 | 10 | //surfix must be '/', only used for dir relative sample 11 | const char DIR_NAME[] = ""; 12 | 13 | -------------------------------------------------------------------------------- /sample/oss_sample_util.h: -------------------------------------------------------------------------------- 1 | #ifndef OSS_SAMPLE_UTIL_H 2 | #define OSS_SAMPLE_UTIL_H 3 | 4 | #include "aos_http_io.h" 5 | #include "aos_string.h" 6 | #include "aos_transport.h" 7 | #include "oss_define.h" 8 | 9 | OSS_CPP_START 10 | 11 | void make_rand_string(aos_pool_t *p, int len, aos_string_t *data); 12 | 13 | aos_buf_t *make_random_buf(aos_pool_t *p, int len); 14 | 15 | void make_random_body(aos_pool_t *p, int count, aos_list_t *bc); 16 | 17 | void init_sample_config(oss_config_t *config, int is_cname); 18 | 19 | void init_sample_request_options(oss_request_options_t *options, int is_cname); 20 | 21 | int64_t get_file_size(const char *file_path); 22 | 23 | OSS_CPP_END 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/aos_fstack.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_FSTACK_H 2 | #define LIBAOS_FSTACK_H 3 | 4 | #include "aos_define.h" 5 | 6 | AOS_CPP_START 7 | 8 | typedef void (*aos_func1_pt)(void*); 9 | typedef void (*aos_func2_pt)(); 10 | typedef int (*aos_func3_pt)(void*); 11 | typedef int (*aos_func4_pt)(); 12 | 13 | typedef union aos_func_u { 14 | aos_func1_pt func1; 15 | aos_func2_pt func2; 16 | aos_func3_pt func3; 17 | aos_func4_pt func4; 18 | } aos_func_u; 19 | 20 | typedef struct aos_fstack_item_t { 21 | void *data; 22 | aos_func_u func; 23 | int order; 24 | } aos_fstack_item_t; 25 | 26 | aos_array_header_t *aos_fstack_create(aos_pool_t *p, int size); 27 | 28 | aos_fstack_item_t *aos_fstack_pop(aos_array_header_t *fstack); 29 | 30 | void aos_fstack_destory(aos_array_header_t *fstack); 31 | 32 | void aos_fstack_push(aos_array_header_t *fstack, void *data, aos_func_u func, int order); 33 | 34 | AOS_CPP_END 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /sample/oss_delete_object_sample.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "aos_util.h" 3 | #include "aos_string.h" 4 | #include "aos_status.h" 5 | #include "oss_auth.h" 6 | #include "oss_util.h" 7 | #include "oss_api.h" 8 | #include "oss_config.h" 9 | #include "oss_sample_util.h" 10 | 11 | void delete_object() 12 | { 13 | aos_pool_t *p = NULL; 14 | aos_string_t bucket; 15 | aos_string_t object; 16 | int is_cname = 0; 17 | oss_request_options_t *options = NULL; 18 | aos_table_t *resp_headers = NULL; 19 | aos_status_t *s = NULL; 20 | 21 | aos_pool_create(&p, NULL); 22 | options = oss_request_options_create(p); 23 | init_sample_request_options(options, is_cname); 24 | aos_str_set(&bucket, BUCKET_NAME); 25 | aos_str_set(&object, OBJECT_NAME); 26 | 27 | s = oss_delete_object(options, &bucket, &object, &resp_headers); 28 | 29 | if (NULL != s && 204 == s->code) { 30 | printf("delete object succeed\n"); 31 | } else { 32 | printf("delete object failed\n"); 33 | } 34 | 35 | aos_pool_destroy(p); 36 | } 37 | 38 | int main(int argc, char *argv[]) 39 | { 40 | if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { 41 | exit(1); 42 | } 43 | 44 | delete_object(); 45 | 46 | aos_http_io_deinitialize(); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/aos_fstack.c: -------------------------------------------------------------------------------- 1 | #include "aos_fstack.h" 2 | 3 | aos_array_header_t *aos_fstack_create(aos_pool_t *p, int size) 4 | { 5 | return apr_array_make(p, size, sizeof(aos_fstack_item_t)); 6 | } 7 | 8 | void aos_fstack_push(aos_array_header_t *fstack, void *data, aos_func_u func, int order) 9 | { 10 | aos_fstack_item_t *item; 11 | 12 | item = (aos_fstack_item_t*)apr_array_push(fstack); 13 | item->data = data; 14 | item->func = func; 15 | item->order = order; 16 | } 17 | 18 | aos_fstack_item_t *aos_fstack_pop(aos_array_header_t *fstack) 19 | { 20 | aos_fstack_item_t *item; 21 | 22 | item = (aos_fstack_item_t*)apr_array_pop(fstack); 23 | if (item == NULL) { 24 | return NULL; 25 | } 26 | 27 | switch (item->order) { 28 | case 1: 29 | item->func.func1(item->data); 30 | break; 31 | case 2: 32 | item->func.func2(); 33 | break; 34 | case 3: 35 | item->func.func3(item->data); 36 | break; 37 | case 4: 38 | item->func.func4(); 39 | break; 40 | default: 41 | break; 42 | } 43 | 44 | return item; 45 | } 46 | 47 | void aos_fstack_destory(aos_array_header_t *fstack) 48 | { 49 | while (aos_fstack_pop(fstack) != NULL); 50 | } 51 | -------------------------------------------------------------------------------- /src/aos_status.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_STATUS_H 2 | #define LIBAOS_STATUS_H 3 | 4 | #include "aos_define.h" 5 | #include "aos_list.h" 6 | 7 | AOS_CPP_START 8 | 9 | typedef struct aos_status_s aos_status_t; 10 | 11 | struct aos_status_s { 12 | int code; // > 0 http code 13 | char *error_code; // can't modify 14 | char *error_msg; // can't modify 15 | char *req_id; // can't modify 16 | }; 17 | 18 | static inline int aos_status_is_ok(aos_status_t *s) 19 | { 20 | return s->code > 0 && s->code / 100 == 2; 21 | } 22 | 23 | static inline int aos_http_is_ok(int st) 24 | { 25 | return st / 100 == 2; 26 | } 27 | 28 | #define aos_status_set(s, c, ec, es) \ 29 | (s)->code = c; (s)->error_code = (char *)ec; (s)->error_msg = (char *)es 30 | 31 | aos_status_t *aos_status_create(aos_pool_t *p); 32 | 33 | aos_status_t *aos_status_dup(aos_pool_t *p, aos_status_t *src); 34 | 35 | aos_status_t *aos_status_parse_from_body(aos_pool_t *p, aos_list_t *bc, int code, aos_status_t *s); 36 | 37 | extern const char AOS_XML_PARSE_ERROR_CODE[]; 38 | extern const char AOS_OPEN_FILE_ERROR_CODE[]; 39 | extern const char AOS_HTTP_IO_ERROR_CODE[]; 40 | extern const char AOS_UNKNOWN_ERROR_CODE[]; 41 | extern const char AOS_CLIENT_ERROR_CODE[]; 42 | extern const char AOS_UTF8_ENCODE_ERROR_CODE[]; 43 | 44 | AOS_CPP_END 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /sample/oss_head_object_sample.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "aos_util.h" 3 | #include "aos_string.h" 4 | #include "aos_status.h" 5 | #include "oss_auth.h" 6 | #include "oss_util.h" 7 | #include "oss_api.h" 8 | #include "oss_config.h" 9 | #include "oss_sample_util.h" 10 | 11 | void head_object() 12 | { 13 | aos_pool_t *p = NULL; 14 | aos_string_t bucket; 15 | aos_string_t object; 16 | int is_cname = 0; 17 | oss_request_options_t *options = NULL; 18 | aos_table_t *headers = NULL; 19 | aos_table_t *resp_headers = NULL; 20 | aos_status_t *s = NULL; 21 | 22 | aos_pool_create(&p, NULL); 23 | options = oss_request_options_create(p); 24 | init_sample_request_options(options, is_cname); 25 | aos_str_set(&bucket, BUCKET_NAME); 26 | aos_str_set(&object, OBJECT_NAME); 27 | headers = aos_table_make(p, 0); 28 | 29 | s = oss_head_object(options, &bucket, &object, headers, &resp_headers); 30 | 31 | if (NULL != s && 2 == s->code / 100) { 32 | printf("head object succeeded\n"); 33 | } else { 34 | printf("head object failed\n"); 35 | } 36 | 37 | aos_pool_destroy(p); 38 | } 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { 43 | exit(1); 44 | } 45 | 46 | head_object(); 47 | 48 | aos_http_io_deinitialize(); 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /src/aos_string.c: -------------------------------------------------------------------------------- 1 | #include "aos_string.h" 2 | 3 | typedef int (*aos_is_char_pt)(char c); 4 | 5 | static void aos_strip_str_func(aos_string_t *str, aos_is_char_pt func); 6 | 7 | char *aos_pstrdup(aos_pool_t *p, const aos_string_t *s) 8 | { 9 | return apr_pstrndup(p, s->data, s->len); 10 | } 11 | 12 | static void aos_strip_str_func(aos_string_t *str, aos_is_char_pt func) 13 | { 14 | char *data = str->data; 15 | int len = str->len; 16 | int offset = 0; 17 | 18 | if (len == 0) return; 19 | 20 | while (len > 0 && func(data[len - 1])) { 21 | --len; 22 | } 23 | 24 | for (; offset < len && func(data[offset]); ++offset) { 25 | // empty; 26 | } 27 | 28 | str->data = data + offset; 29 | str->len = len - offset; 30 | } 31 | 32 | void aos_unquote_str(aos_string_t *str) 33 | { 34 | aos_strip_str_func(str, aos_is_quote); 35 | } 36 | 37 | void aos_strip_space(aos_string_t *str) 38 | { 39 | aos_strip_str_func(str, aos_is_space); 40 | } 41 | 42 | void aos_trip_space_and_cntrl(aos_string_t *str) 43 | { 44 | aos_strip_str_func(str, aos_is_space_or_cntrl); 45 | } 46 | 47 | int aos_ends_with(const aos_string_t *str, const aos_string_t *suffix) 48 | { 49 | if (!str || !suffix) { 50 | return 0; 51 | } 52 | 53 | return (str->len >= suffix->len) && strncmp(str->data + str->len - suffix->len, suffix->data, suffix->len) == 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/aos_string.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_STRING_H 2 | #define LIBAOS_STRING_H 3 | 4 | #include "aos_define.h" 5 | 6 | AOS_CPP_START 7 | 8 | typedef struct { 9 | int len; 10 | char *data; 11 | } aos_string_t; 12 | 13 | #define aos_string(str) { sizeof(str) - 1, (char *) str } 14 | #define aos_null_string { 0, NULL } 15 | #define aos_str_set(str, text) \ 16 | (str)->len = strlen(text); (str)->data = (char *) text 17 | #define aos_str_null(str) (str)->len = 0; (str)->data = NULL 18 | 19 | #define aos_tolower(c) (char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c) 20 | #define aos_toupper(c) (char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c) 21 | 22 | static inline void aos_string_tolower(aos_string_t *str) 23 | { 24 | int i = 0; 25 | while (i < str->len) { 26 | str->data[i] = aos_tolower(str->data[i]); 27 | ++i; 28 | } 29 | } 30 | 31 | static inline char *aos_strlchr(char *p, char *last, char c) 32 | { 33 | while (p < last) { 34 | if (*p == c) { 35 | return p; 36 | } 37 | p++; 38 | } 39 | return NULL; 40 | } 41 | 42 | static inline int aos_is_quote(char c) 43 | { 44 | return c == '\"'; 45 | } 46 | 47 | static inline int aos_is_space(char c) 48 | { 49 | return ((c == ' ') || (c == '\t')); 50 | } 51 | 52 | static inline int aos_is_space_or_cntrl(char c) 53 | { 54 | return c <= ' '; 55 | } 56 | 57 | void aos_strip_space(aos_string_t *str); 58 | void aos_trip_space_and_cntrl(aos_string_t *str); 59 | void aos_unquote_str(aos_string_t *str); 60 | 61 | char *aos_pstrdup(aos_pool_t *p, const aos_string_t *s); 62 | 63 | int aos_ends_with(const aos_string_t *str, const aos_string_t *suffix); 64 | 65 | AOS_CPP_END 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/aos_buf.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_BUF_H 2 | #define LIBAOS_BUF_H 3 | 4 | #include "aos_define.h" 5 | #include "aos_list.h" 6 | 7 | AOS_CPP_START 8 | 9 | typedef struct { 10 | aos_list_t node; 11 | uint8_t *pos; 12 | uint8_t *last; 13 | uint8_t *start; 14 | uint8_t *end; 15 | } aos_buf_t; 16 | 17 | typedef struct { 18 | aos_list_t node; 19 | int64_t file_pos; 20 | int64_t file_last; 21 | apr_file_t *file; 22 | uint32_t owner:1; 23 | } aos_file_buf_t; 24 | 25 | aos_buf_t *aos_create_buf(aos_pool_t *p, int size); 26 | #define aos_buf_size(b) (b->last - b->pos) 27 | 28 | aos_file_buf_t *aos_create_file_buf(aos_pool_t *p); 29 | 30 | aos_buf_t *aos_buf_pack(aos_pool_t *p, const void *data, int size); 31 | 32 | int64_t aos_buf_list_len(aos_list_t *list); 33 | 34 | char *aos_buf_list_content(aos_pool_t *p, aos_list_t *list); 35 | 36 | void aos_buf_append_string(aos_pool_t *p, aos_buf_t *b, const char *str, int len); 37 | 38 | /** 39 | * @param fb file_pos, file_last equal file_size. 40 | * @return AOSE_OK success, other failure. 41 | */ 42 | int aos_open_file_for_read(aos_pool_t *p, const char *path, aos_file_buf_t *fb); 43 | 44 | int aos_open_file_for_all_read(aos_pool_t *p, const char *path, aos_file_buf_t *fb); 45 | 46 | int aos_open_file_for_range_read(aos_pool_t *p, const char *path, 47 | int64_t file_pos, int64_t file_last, 48 | aos_file_buf_t *fb); 49 | 50 | /** 51 | * create the file if not there, truncate if file exists. 52 | * @param fb not check file_pos, file_last. 53 | * @return AOSE_OK success, other failure. 54 | */ 55 | int aos_open_file_for_write(aos_pool_t *p, const char *path, aos_file_buf_t *fb); 56 | 57 | AOS_CPP_END 58 | 59 | #endif 60 | 61 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project (oss_c_sdk_test) 2 | 3 | include_directories(${CMAKE_SOURCE_DIR}) 4 | 5 | configure_file ( 6 | "${PROJECT_SOURCE_DIR}/test.h.in" 7 | "${PROJECT_SOURCE_DIR}/test.h" 8 | ) 9 | 10 | set(SAMPLE_SOURCE_FILES CuTest.c oss_test_util.c oss_config.c test_oss_bucket.c test_oss_object.c test_oss_multipart.c test_aos.c test_all.c) 11 | 12 | # find_path(APR_INCLUDE_DIR apr-1/apr_time.h) 13 | # find_path(APR_UTIL_INCLUDE_DIR apr/include/apr-1/apr_md5.h) 14 | # find_path(MINIXML_INCLUDE_DIR mxml.h) 15 | # find_path(CURL_INCLUDE_DIR curl/curl.h) 16 | 17 | include_directories (${APR_INCLUDE_DIR}) 18 | include_directories (${APR_UTIL_INCLUDE_DIR}) 19 | include_directories (${MINIXML_INCLUDE_DIR}) 20 | include_directories (${CURL_INCLUDE_DIR}) 21 | include_directories ("${CMAKE_SOURCE_DIR}/src") 22 | 23 | find_library(APR_LIBRARY apr-1 PATHS /usr/local/apr/lib/) 24 | find_library(APR_UTIL_LIBRARY aprutil-1 PATHS /usr/local/apr/lib/) 25 | find_library(MINIXML_LIBRARY mxml) 26 | find_library(CURL_LIBRARY curl) 27 | find_library(PTHREAD_LIBRARY pthread) 28 | #find_library(SSL_LIBRARY ssl) 29 | #find_library(IDN_LIBRARY idn) 30 | find_library(RT_LIBRARY rt) 31 | #find_library(OSS_C_SDK_LIBRARY oss_c_sdk HINTS ${LIBRARY_OUTPUT_PATH}) 32 | 33 | add_executable(oss_c_sdk_test ${SAMPLE_SOURCE_FILES}) 34 | 35 | target_link_libraries(oss_c_sdk_test oss_c_sdk) 36 | target_link_libraries(oss_c_sdk_test ${APR_UTIL_LIBRARY}) 37 | target_link_libraries(oss_c_sdk_test ${APR_LIBRARY}) 38 | target_link_libraries(oss_c_sdk_test ${MINIXML_LIBRARY}) 39 | target_link_libraries(oss_c_sdk_test ${CURL_LIBRARY}) 40 | target_link_libraries(oss_c_sdk_test ${PTHREAD_LIBRARY}) 41 | #target_link_libraries(oss_c_sdk_test ${SSL_LIBRARY}) 42 | #target_link_libraries(oss_c_sdk_test ${IDN_LIBRARY}) 43 | target_link_libraries(oss_c_sdk_test ${RT_LIBRARY}) 44 | -------------------------------------------------------------------------------- /src/oss_auth.h: -------------------------------------------------------------------------------- 1 | #ifndef LIB_OSS_AUTH_H 2 | #define LIB_OSS_AUTH_H 3 | 4 | #include "aos_util.h" 5 | #include "aos_string.h" 6 | #include "aos_http_io.h" 7 | #include "oss_define.h" 8 | 9 | OSS_CPP_START 10 | 11 | /** 12 | * @brief sign oss headers 13 | **/ 14 | void oss_sign_headers(aos_pool_t *p, 15 | const aos_string_t *signstr, 16 | const aos_string_t *access_key_id, 17 | const aos_string_t *access_key_secret, 18 | aos_table_t *headers); 19 | 20 | /** 21 | * @brief get string to signature 22 | **/ 23 | int oss_get_string_to_sign(aos_pool_t *p, 24 | http_method_e method, 25 | const aos_string_t *canon_res, 26 | const aos_table_t *headers, 27 | const aos_table_t *params, 28 | aos_string_t *signstr); 29 | 30 | /** 31 | * @brief get signed oss request headers 32 | **/ 33 | int oss_get_signed_headers(aos_pool_t *p, const aos_string_t *access_key_id, 34 | const aos_string_t *access_key_secret, 35 | const aos_string_t* canon_res, aos_http_request_t *req); 36 | 37 | /** 38 | * @brief sign oss request 39 | **/ 40 | int oss_sign_request(aos_http_request_t *req, const oss_config_t *config); 41 | 42 | /** 43 | * @brief generate oss request Signature 44 | **/ 45 | int get_oss_request_signature(const oss_request_options_t *options, aos_http_request_t *req, 46 | const aos_string_t *expires, aos_string_t *signature); 47 | 48 | /** 49 | * @brief get oss signed url 50 | **/ 51 | int oss_get_signed_url(const oss_request_options_t *options, aos_http_request_t *req, 52 | const aos_string_t *expires, aos_string_t *auth_url); 53 | 54 | OSS_CPP_END 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/oss_define.c: -------------------------------------------------------------------------------- 1 | #include "oss_define.h" 2 | 3 | const char OSS_CANNONICALIZED_HEADER_PREFIX[] = "x-oss-"; 4 | const char OSS_CANNONICALIZED_HEADER_DATE[] = "x-oss-date"; 5 | const char OSS_CANNONICALIZED_HEADER_ACL[] = "x-oss-acl"; 6 | const char OSS_CANNONICALIZED_HEADER_COPY_SOURCE[] = "x-oss-copy-source"; 7 | const char OSS_CONTENT_MD5[] = "Content-MD5"; 8 | const char OSS_CONTENT_TYPE[] = "Content-Type"; 9 | const char OSS_DATE[] = "Date"; 10 | const char OSS_AUTHORIZATION[] = "Authorization"; 11 | const char OSS_ACCESSKEYID[] = "OSSAccessKeyId"; 12 | const char OSS_EXPIRES[] = "Expires"; 13 | const char OSS_SIGNATURE[] = "Signature"; 14 | const char OSS_ACL[] = "acl"; 15 | const char OSS_PREFIX[] = "prefix"; 16 | const char OSS_DELIMITER[] = "delimiter"; 17 | const char OSS_MARKER[] = "marker"; 18 | const char OSS_MAX_KEYS[] = "max-keys"; 19 | const char OSS_UPLOADS[] = "uploads"; 20 | const char OSS_UPLOAD_ID[] = "uploadId"; 21 | const char OSS_MAX_PARTS[] = "max-parts"; 22 | const char OSS_PART_NUMBER_MARKER[] = "part-number-marker"; 23 | const char OSS_KEY_MARKER[] = "key-marker"; 24 | const char OSS_UPLOAD_ID_MARKER[] = "upload-id-marker"; 25 | const char OSS_MAX_UPLOADS[] = "max-uploads"; 26 | const char OSS_PARTNUMBER[] = "partNumber"; 27 | const char OSS_APPEND[] = "append"; 28 | const char OSS_POSITION[] = "position"; 29 | const char OSS_MULTIPART_CONTENT_TYPE[] = "application/x-www-form-urlencoded"; 30 | const char OSS_COPY_SOURCE[] = "x-oss-copy-source"; 31 | const char OSS_COPY_SOURCE_RANGE[] = "x-oss-copy-source-range"; 32 | const char OSS_STS_SECURITY_TOKEN[] = "x-oss-security-token"; 33 | const char OSS_REPLACE_OBJECT_META[] = "x-oss-replace-object-meta"; 34 | const char OSS_LIFECYCLE[] = "lifecycle"; 35 | const char OSS_DELETE[] = "delete"; 36 | const char OSS_YES[] = "yes"; 37 | const int OSS_MAX_PART_NUM = 10000; 38 | const int OSS_PER_RET_NUM = 1000; 39 | const int MAX_SUFFIX_LEN = 1024; 40 | -------------------------------------------------------------------------------- /src/aos_util.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_UTIL_H 2 | #define LIBAOS_UTIL_H 3 | 4 | #include "aos_buf.h" 5 | #include "aos_string.h" 6 | #include "aos_define.h" 7 | #include "aos_fstack.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | AOS_CPP_START 14 | 15 | int aos_parse_xml_body(aos_list_t *bc, mxml_node_t **root); 16 | 17 | void aos_gnome_sort(const char **headers, int size); 18 | 19 | int aos_convert_to_gmt_time(char* date, const char* format, apr_time_exp_t *tm); 20 | int aos_get_gmt_str_time(char datestr[AOS_MAX_GMT_TIME_LEN]); 21 | 22 | /** 23 | * URL-encodes a string from [src] into [dest]. [dest] must have at least 24 | * 3x the number of characters that [source] has. At most [maxSrcSize] bytes 25 | * from [src] are encoded; if more are present in [src], 0 is returned from 26 | * urlEncode, else nonzero is returned. 27 | */ 28 | int aos_url_encode(char *dest, const char *src, int maxSrcSize); 29 | 30 | const char* aos_http_method_to_string(http_method_e method); 31 | 32 | /** 33 | * encode query string, check query args < AOS_MAX_QUERY_ARG_LEN 34 | * result string "?a&b=x" 35 | */ 36 | int aos_query_params_to_string(aos_pool_t *p, aos_table_t *query_params, aos_string_t *querystr); 37 | 38 | /** 39 | * base64 encode bytes. The output buffer must have at least 40 | * ((4 * (inLen + 1)) / 3) bytes in it. Returns the number of bytes written 41 | * to [out]. 42 | */ 43 | int aos_base64_encode(const unsigned char *in, int inLen, char *out); 44 | 45 | /** 46 | * Compute HMAC-SHA-1 with key [key] and message [message], storing result 47 | * in [hmac] 48 | */ 49 | void HMAC_SHA1(unsigned char hmac[20], const unsigned char *key, int key_len, 50 | const unsigned char *message, int message_len); 51 | 52 | unsigned char* aos_md5(aos_pool_t* pool, const char* in, apr_size_t in_len); 53 | 54 | int aos_url_decode(const char *in, char *out); 55 | 56 | AOS_CPP_END 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/aos_http_io.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_HTTP_IO_H 2 | #define LIBAOS_HTTP_IO_H 3 | 4 | #include "aos_transport.h" 5 | 6 | AOS_CPP_START 7 | 8 | aos_http_controller_t *aos_http_controller_create(aos_pool_t *p, int owner); 9 | 10 | // http io error message 11 | static inline const char *aos_http_controller_get_reason(aos_http_controller_t *ctl) 12 | { 13 | aos_http_controller_ex_t *ctle = (aos_http_controller_ex_t *)ctl; 14 | return ctle->reason; 15 | } 16 | 17 | CURL *aos_request_get(); 18 | void request_release(CURL *request); 19 | 20 | int aos_http_io_initialize(const char *user_agent_info, int flag); 21 | void aos_http_io_deinitialize(); 22 | 23 | int aos_http_send_request(aos_http_controller_t *ctl, aos_http_request_t *req, aos_http_response_t *resp); 24 | 25 | void aos_set_default_request_options(aos_http_request_options_t *op); 26 | void aos_set_default_transport_options(aos_http_transport_options_t *op); 27 | 28 | aos_http_request_options_t *aos_http_request_options_create(aos_pool_t *p); 29 | 30 | aos_http_request_t *aos_http_request_create(aos_pool_t *p); 31 | aos_http_response_t *aos_http_response_create(aos_pool_t *p); 32 | 33 | int aos_read_http_body_memory(aos_http_request_t *req, char *buffer, int len); 34 | int aos_write_http_body_memory(aos_http_response_t *resp, const char *buffer, int len); 35 | 36 | int aos_read_http_body_file(aos_http_request_t *req, char *buffer, int len); 37 | int aos_write_http_body_file(aos_http_response_t *resp, const char *buffer, int len); 38 | 39 | typedef aos_http_transport_t *(*aos_http_transport_create_pt)(aos_pool_t *p); 40 | typedef int (*aos_http_transport_perform_pt)(aos_http_transport_t *t); 41 | 42 | extern aos_pool_t *aos_global_pool; 43 | extern apr_file_t *aos_stderr_file; 44 | 45 | extern aos_http_request_options_t *aos_default_http_request_options; 46 | extern aos_http_transport_options_t *aos_default_http_transport_options; 47 | 48 | extern aos_http_transport_create_pt aos_http_transport_create; 49 | extern aos_http_transport_perform_pt aos_http_transport_perform; 50 | 51 | AOS_CPP_END 52 | 53 | #endif 54 | 55 | -------------------------------------------------------------------------------- /src/aos_log.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "apr_portable.h" 3 | 4 | aos_log_print_pt aos_log_print = aos_log_print_default; 5 | aos_log_format_pt aos_log_format = aos_log_format_default; 6 | aos_log_level_e aos_log_level = AOS_LOG_WARN; 7 | 8 | extern apr_file_t *aos_stderr_file; 9 | 10 | void aos_log_set_print(aos_log_print_pt p) 11 | { 12 | aos_log_print = p; 13 | } 14 | 15 | void aos_log_set_format(aos_log_format_pt p) 16 | { 17 | aos_log_format = p; 18 | } 19 | 20 | void aos_log_set_level(aos_log_level_e level) 21 | { 22 | aos_log_level = level; 23 | } 24 | 25 | void aos_log_set_output(apr_file_t *output) 26 | { 27 | aos_stderr_file = output; 28 | } 29 | 30 | void aos_log_print_default(const char *message, int len) 31 | { 32 | if (aos_stderr_file == NULL) { 33 | fprintf(stderr, "%s", message); 34 | } else { 35 | apr_size_t bnytes = len; 36 | apr_file_write(aos_stderr_file, message, &bnytes); 37 | } 38 | } 39 | 40 | void aos_log_format_default(int level, 41 | const char *file, 42 | int line, 43 | const char *function, 44 | const char *fmt, ...) 45 | { 46 | int len; 47 | apr_time_t t; 48 | int s; 49 | apr_time_exp_t tm; 50 | va_list args; 51 | char buffer[4096]; 52 | 53 | t = apr_time_now(); 54 | if ((s = apr_time_exp_lt(&tm, t)) != APR_SUCCESS) { 55 | return; 56 | } 57 | 58 | len = snprintf(buffer, 4090, "[%04d-%02d-%02d %02d:%02d:%02d.%03d] %" APR_INT64_T_FMT " %s:%d ", 59 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 60 | tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000, 61 | (int64_t)apr_os_thread_current(), file, line); 62 | 63 | va_start(args, fmt); 64 | len += vsnprintf(buffer + len, 4090 - len, fmt, args); 65 | va_end(args); 66 | 67 | while (buffer[len -1] == '\n') len--; 68 | buffer[len++] = '\n'; 69 | buffer[len] = '\0'; 70 | 71 | aos_log_print(buffer, len); 72 | } 73 | 74 | -------------------------------------------------------------------------------- /sample/oss_sample_util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "oss_config.h" 3 | #include "oss_api.h" 4 | #include "oss_sample_util.h" 5 | 6 | void make_rand_string(aos_pool_t *p, int len, aos_string_t *data) 7 | { 8 | char *str = NULL; 9 | int i = 0; 10 | str = (char *)aos_palloc(p, len + 1); 11 | for ( ; i < len; i++) { 12 | str[i] = rand() % 128; 13 | } 14 | str[len] = '\0'; 15 | aos_str_set(data, str); 16 | } 17 | 18 | aos_buf_t *make_random_buf(aos_pool_t *p, int len) 19 | { 20 | int bytes; 21 | aos_buf_t *b; 22 | aos_string_t str; 23 | 24 | make_rand_string(p, 16, &str); 25 | b = aos_create_buf(p, len); 26 | 27 | while (b->last < b->end) { 28 | bytes = b->end - b->last; 29 | bytes = aos_min(bytes, 16); 30 | memcpy(b->last, str.data, bytes); 31 | b->last += bytes; 32 | } 33 | 34 | return b; 35 | } 36 | 37 | void make_random_body(aos_pool_t *p, int count, aos_list_t *bc) 38 | { 39 | int i = 0; 40 | int len; 41 | aos_buf_t *b; 42 | 43 | for (; i < count; ++i) { 44 | len = random() % 4096; 45 | b = make_random_buf(p, len); 46 | aos_list_add_tail(&b->node, bc); 47 | } 48 | } 49 | 50 | void init_sample_config(oss_config_t *config, int is_cname) 51 | { 52 | aos_str_set(&config->endpoint, OSS_ENDPOINT); 53 | aos_str_set(&config->access_key_id, ACCESS_KEY_ID); 54 | aos_str_set(&config->access_key_secret, ACCESS_KEY_SECRET); 55 | config->is_cname = is_cname; 56 | } 57 | 58 | void init_sample_request_options(oss_request_options_t *options, int is_cname) 59 | { 60 | options->config = oss_config_create(options->pool); 61 | init_sample_config(options->config, is_cname); 62 | options->ctl = aos_http_controller_create(options->pool, 0); 63 | } 64 | 65 | int64_t get_file_size(const char *file_path) 66 | { 67 | int64_t filesize = -1; 68 | struct stat statbuff; 69 | 70 | if(stat(file_path, &statbuff) < 0){ 71 | return filesize; 72 | } else { 73 | filesize = statbuff.st_size; 74 | } 75 | 76 | return filesize; 77 | } 78 | -------------------------------------------------------------------------------- /test/oss_test_util.h: -------------------------------------------------------------------------------- 1 | #ifndef OSS_TEST_UTIL_H 2 | #define OSS_TEST_UTIL_H 3 | 4 | #include "CuTest.h" 5 | #include "aos_http_io.h" 6 | #include "aos_string.h" 7 | #include "aos_transport.h" 8 | #include "aos_status.h" 9 | #include "oss_define.h" 10 | 11 | OSS_CPP_START 12 | 13 | #define test_object_base() do { \ 14 | aos_str_set(&bucket, bucket_name); \ 15 | aos_str_set(&object, object_name); \ 16 | } while(0) 17 | 18 | void make_rand_string(aos_pool_t *p, int len, aos_string_t *data); 19 | 20 | aos_buf_t *make_random_buf(aos_pool_t *p, int len); 21 | 22 | void make_random_body(aos_pool_t *p, int count, aos_list_t *bc); 23 | 24 | void init_test_config(oss_config_t *config, int is_cname); 25 | 26 | void init_test_request_options(oss_request_options_t *options, int is_cname); 27 | 28 | aos_status_t * create_test_bucket(const oss_request_options_t *options, 29 | const char *bucket_name, oss_acl_e oss_acl); 30 | 31 | aos_status_t *create_test_object(const oss_request_options_t *options, const char *bucket_name, 32 | const char *object_name, const char *data, aos_table_t *headers); 33 | 34 | aos_status_t *create_test_object_from_file(const oss_request_options_t *options, const char *bucket_name, 35 | const char *object_name, const char *filename, aos_table_t *headers); 36 | 37 | aos_status_t *delete_test_object(const oss_request_options_t *options, 38 | const char *bucket_name, const char *object_name); 39 | 40 | aos_status_t *init_test_multipart_upload(const oss_request_options_t *options, const char *bucket_name, 41 | const char *object_name, aos_string_t *upload_id); 42 | 43 | aos_status_t *abort_test_multipart_upload(const oss_request_options_t *options, const char *bucket_name, 44 | const char *object_name, aos_string_t *upload_id); 45 | 46 | char *gen_test_signed_url(const oss_request_options_t *options, const char *bucket_name, 47 | const char *object_name, int64_t expires, aos_http_request_t *req); 48 | 49 | unsigned long get_file_size(const char *file_path); 50 | 51 | OSS_CPP_END 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ChangeLog - Aliyun OSS SDK for C 2 | 3 | ## 版本号:2.0.0 日期:2016-03-08 4 | ### 变更内容 5 | - complete multipart接口支持覆盖原有head 6 | - 重构示例程序和组织方式 7 | - 开放params参数,允许用户自定义设置 8 | - 允许params和headers参数为空,简化使用 9 | - 支持https 10 | - 支持ip 11 | - 新增部分测试 12 | - 新增oss_put_bucket_acl接口 13 | - 新增目录相关示例 14 | - 新增signed url相关示例 15 | - 完善接口注释 16 | - 删除无用的port配置参数 17 | - 调整oss_init_multipart_upload接口参数顺序 18 | - 优化配置参数名称,使其与官方网站保持一致 19 | - 解决endpoint不能含有http等前缀的问题 20 | - 解决用户无法设置content-type的问题 21 | - 解决无法自动根据file name和key设置content-type的问题 22 | - 解决list upload parts为空时coredump的问题 23 | - 解决oss_upload_file接口在断点续传时可能会coredump的问题 24 | - 解决部分单词拼写错误 25 | - 解决所有警告 26 | - 解决部分头文件宏保护无效的问题 27 | - 解决oss_head_object_by_url接口不生效的问题 28 | 29 | 30 | ## 版本号:1.0.0 日期:2015-12-16 31 | ### 变更内容 32 | - 调整OSS C SDK依赖的XML第三方库,使用minixml替换libxml减小OSS C SDK的大小 33 | - 修改编译方式为CMAKE,同时提供嵌入式环境的Makefile.embeded,减少automake重复编译的问题 34 | - 新增oss_upload_file接口,封装multipart upload相关的接口,使用multipart方式上传文件 35 | - 新增oss_delete_objects_by_prefix接口,删除指定prefix的object 36 | - 新增OSS C SDK根据object name或者filename自动添加content_type 37 | - 完善OSS C SDK demo的调用示例,方便用户快速入门 38 | 39 | ## 版本号:0.0.7 日期:2015-11-11 40 | ### 变更内容 41 | - OSS C SDK修复sts_token超过http header最大限制的问题 42 | 43 | ## 版本号:0.0.6 日期:2015-10-29 44 | ### 变更内容 45 | - OSS C SDK签名时请求头支持x-oss-date,允许用户指定签名时间,解决系统时间偏差导致签名出错的问题 46 | - OSS C SDK支持CNAME方式访问OSS,CNAME方式请求时指定is_oss_domain值为0 47 | - 新增OSS C SDK demo,提供简单的接口调用示例,方便用户快速入门 48 | - OSS C SDK sample示例中去除对utf8第三方库的依赖 49 | 50 | ## 版本号:0.0.5 日期:2015-09-10 51 | ### 变更内容 52 | - 调整OSS C SDK获取GMT时间的方式,解决LOCALE变化可能导致签名出错的问题 53 | - aos_status_t结构体增加req_id字段,方便定位请求出错问题 54 | 55 | ## 版本号:0.0.4 日期:2015-07-27 56 | ### 变更内容 57 | - 增加生命周期相关的接口oss_put_bucket_lifecycle、oss_get_bucket_lifecycle以及oss_delete_bucket_lifecycle 58 | - OSS C SDK支持长连接,默认使用连接池支持keep alive功能 59 | - oss_list_object增加子目录的输出 60 | 61 | ## 版本号:0.0.3 日期:2015-07-08 62 | ### 变更内容 63 | - 增加oss_append_object_from_buffer接口,支持追加上传buffer中的内容到object 64 | - 增加oss_append_object_from_file接口,支持追加上传文件中的内容到object 65 | 66 | ## 版本号:0.0.2 日期:2015-06-10 67 | ### 变更内容 68 | - 增加oss_upload_part_copy,支持Upload Part Copy方式拷贝 69 | - 增加sts服务临时授权方式访问OSS 70 | 71 | ## 版本号:0.0.1 日期:2015-05-28 72 | ### 变更内容 73 | - 基于OSS API文档,提供OSS bucket、object以及multipart相关的常见操作API 74 | - 提供基于CuTest的sample 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/aos_log.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_LOG_H 2 | #define LIBAOS_LOG_H 3 | 4 | #include "aos_define.h" 5 | 6 | AOS_CPP_START 7 | 8 | typedef void (*aos_log_print_pt)(const char *message, int len); 9 | 10 | typedef void (*aos_log_format_pt)(int level, 11 | const char *file, 12 | int line, 13 | const char *function, 14 | const char *fmt, ...) 15 | __attribute__ ((__format__ (__printf__, 5, 6))); 16 | 17 | void aos_log_set_print(aos_log_print_pt p); 18 | void aos_log_set_format(aos_log_format_pt p); 19 | 20 | typedef enum { 21 | AOS_LOG_OFF = 1, 22 | AOS_LOG_FATAL, 23 | AOS_LOG_ERROR, 24 | AOS_LOG_WARN, 25 | AOS_LOG_INFO, 26 | AOS_LOG_DEBUG, 27 | AOS_LOG_TRACE, 28 | AOS_LOG_ALL 29 | } aos_log_level_e; 30 | 31 | #define aos_fatal_log(format, args...) if(aos_log_level>=AOS_LOG_FATAL) \ 32 | aos_log_format(AOS_LOG_FATAL, __FILE__, __LINE__, __FUNCTION__, format, ## args) 33 | #define aos_error_log(format, args...) if(aos_log_level>=AOS_LOG_ERROR) \ 34 | aos_log_format(AOS_LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, format, ## args) 35 | #define aos_warn_log(format, args...) if(aos_log_level>=AOS_LOG_WARN) \ 36 | aos_log_format(AOS_LOG_WARN, __FILE__, __LINE__, __FUNCTION__, format, ## args) 37 | #define aos_info_log(format, args...) if(aos_log_level>=AOS_LOG_INFO) \ 38 | aos_log_format(AOS_LOG_INFO, __FILE__, __LINE__, __FUNCTION__, format, ## args) 39 | #define aos_debug_log(format, args...) if(aos_log_level>=AOS_LOG_DEBUG) \ 40 | aos_log_format(AOS_LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, format, ## args) 41 | #define aos_trace_log(format, args...) if(aos_log_level>=AOS_LOG_TRACE) \ 42 | aos_log_format(AOS_LOG_TRACE, __FILE__, __LINE__, __FUNCTION__, format, ## args) 43 | 44 | void aos_log_set_level(aos_log_level_e level); 45 | 46 | void aos_log_set_output(apr_file_t *output); 47 | 48 | void aos_log_print_default(const char *message, int len); 49 | 50 | void aos_log_format_default(int level, 51 | const char *file, 52 | int line, 53 | const char *function, 54 | const char *fmt, ...) 55 | __attribute__ ((__format__ (__printf__, 5, 6))); 56 | 57 | extern aos_log_level_e aos_log_level; 58 | extern aos_log_format_pt aos_log_format; 59 | extern aos_log_format_pt aos_log_format; 60 | 61 | AOS_CPP_END 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /sample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project (oss_c_sdk_sample) 2 | 3 | include_directories(${CMAKE_SOURCE_DIR}) 4 | 5 | set(PUT_OBJECT_SOURCE_FILES oss_sample_util.c 6 | oss_config.c 7 | oss_put_object_sample.c) 8 | 9 | set(APPEND_OBJECT_SOURCE_FILES oss_sample_util.c 10 | oss_config.c 11 | oss_append_object_sample.c) 12 | 13 | set(GET_OBJECT_SOURCE_FILES oss_sample_util.c 14 | oss_config.c 15 | oss_get_object_sample.c) 16 | 17 | set(HEAD_OBJECT_SOURCE_FILES oss_sample_util.c 18 | oss_config.c 19 | oss_head_object_sample.c) 20 | 21 | set(DELETE_OBJECT_SOURCE_FILES oss_sample_util.c 22 | oss_config.c 23 | oss_delete_object_sample.c) 24 | 25 | set(MULTIPART_UPLOAD_SOURCE_FILES oss_sample_util.c 26 | oss_config.c 27 | oss_multipart_upload_sample.c) 28 | 29 | include_directories (${APR_INCLUDE_DIR}) 30 | include_directories (${APR_UTIL_INCLUDE_DIR}) 31 | include_directories (${MINIXML_INCLUDE_DIR}) 32 | include_directories (${CURL_INCLUDE_DIR}) 33 | include_directories ("${CMAKE_SOURCE_DIR}/src") 34 | 35 | find_library(APR_LIBRARY apr-1 PATHS /usr/local/apr/lib/) 36 | find_library(APR_UTIL_LIBRARY aprutil-1 PATHS /usr/local/apr/lib/) 37 | find_library(MINIXML_LIBRARY mxml) 38 | find_library(CURL_LIBRARY curl) 39 | find_library(PTHREAD_LIBRARY pthread) 40 | find_library(RT_LIBRARY rt) 41 | find_library(M_LIBRARY m) 42 | 43 | function(_TARGET_SAMPLE_LIBRARIES SAMPLE_BIN_NAME SOURCE_FILES) 44 | add_executable(${SAMPLE_BIN_NAME} ${SOURCE_FILES}) 45 | target_link_libraries(${SAMPLE_BIN_NAME} oss_c_sdk) 46 | target_link_libraries(${SAMPLE_BIN_NAME} ${APR_UTIL_LIBRARY}) 47 | target_link_libraries(${SAMPLE_BIN_NAME} ${APR_LIBRARY}) 48 | target_link_libraries(${SAMPLE_BIN_NAME} ${MINIXML_LIBRARY}) 49 | target_link_libraries(${SAMPLE_BIN_NAME} ${CURL_LIBRARY}) 50 | target_link_libraries(${SAMPLE_BIN_NAME} ${PTHREAD_LIBRARY}) 51 | target_link_libraries(${SAMPLE_BIN_NAME} ${RT_LIBRARY}) 52 | target_link_libraries(${SAMPLE_BIN_NAME} ${M_LIBRARY}) 53 | endfunction() 54 | 55 | _TARGET_SAMPLE_LIBRARIES(oss_put_object_sample "${PUT_OBJECT_SOURCE_FILES}") 56 | _TARGET_SAMPLE_LIBRARIES(oss_get_object_sample "${GET_OBJECT_SOURCE_FILES}") 57 | _TARGET_SAMPLE_LIBRARIES(oss_append_object_sample "${APPEND_OBJECT_SOURCE_FILES}") 58 | _TARGET_SAMPLE_LIBRARIES(oss_head_object_sample "${HEAD_OBJECT_SOURCE_FILES}") 59 | _TARGET_SAMPLE_LIBRARIES(oss_delete_object_sample "${DELETE_OBJECT_SOURCE_FILES}") 60 | _TARGET_SAMPLE_LIBRARIES(oss_multipart_upload_sample "${MULTIPART_UPLOAD_SOURCE_FILES}") 61 | -------------------------------------------------------------------------------- /src/aos_status.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "aos_util.h" 3 | #include "aos_status.h" 4 | 5 | const char AOS_XML_PARSE_ERROR_CODE[] = "ParseXmlError"; 6 | const char AOS_OPEN_FILE_ERROR_CODE[] = "OpenFileFail"; 7 | const char AOS_HTTP_IO_ERROR_CODE[] = "HttpIoError"; 8 | const char AOS_UNKNOWN_ERROR_CODE[] = "UnknownError"; 9 | const char AOS_CLIENT_ERROR_CODE[] = "ClientError"; 10 | const char AOS_UTF8_ENCODE_ERROR_CODE[] = "Utf8EncodeFail"; 11 | 12 | aos_status_t *aos_status_create(aos_pool_t *p) 13 | { 14 | return (aos_status_t *)aos_pcalloc(p, sizeof(aos_status_t)); 15 | } 16 | 17 | aos_status_t *aos_status_dup(aos_pool_t *p, aos_status_t *src) 18 | { 19 | aos_status_t *dst = aos_status_create(p); 20 | dst->code = src->code; 21 | dst->error_code = apr_pstrdup(p, src->error_code); 22 | dst->error_msg = apr_pstrdup(p, src->error_msg); 23 | return dst; 24 | } 25 | 26 | aos_status_t *aos_status_parse_from_body(aos_pool_t *p, aos_list_t *bc, int code, aos_status_t *s) 27 | { 28 | int res; 29 | mxml_node_t *root, *node; 30 | mxml_node_t *code_node, *message_node; 31 | char *node_content; 32 | 33 | if (s == NULL) { 34 | s = aos_status_create(p); 35 | } 36 | s->code = code; 37 | 38 | if (aos_http_is_ok(code)) { 39 | return s; 40 | } 41 | 42 | if (aos_list_empty(bc)) { 43 | s->error_code = (char *)AOS_UNKNOWN_ERROR_CODE; 44 | return s; 45 | } 46 | 47 | if ((res = aos_parse_xml_body(bc, &root)) != AOSE_OK) { 48 | s->error_code = (char *)AOS_UNKNOWN_ERROR_CODE; 49 | return s; 50 | } 51 | 52 | node = mxmlFindElement(root, root, "Error",NULL, NULL,MXML_DESCEND); 53 | if (NULL == node) { 54 | char *xml_content = aos_buf_list_content(p, bc); 55 | aos_error_log("Xml format invalid, root node name is not Error.\n"); 56 | aos_error_log("Xml Content:%s\n", xml_content); 57 | s->error_code = (char *)AOS_UNKNOWN_ERROR_CODE; 58 | mxmlDelete(root); 59 | return s; 60 | } 61 | 62 | code_node = mxmlFindElement(node, root, "Code",NULL, NULL,MXML_DESCEND); 63 | if (NULL != code_node) { 64 | node_content = code_node->child->value.opaque; 65 | s->error_code = apr_pstrdup(p, (char *)node_content); 66 | } 67 | 68 | message_node = mxmlFindElement(node, root, "Message",NULL, NULL,MXML_DESCEND); 69 | if (NULL != message_node) { 70 | node_content = message_node->child->value.opaque; 71 | s->error_msg = apr_pstrdup(p, (char *)node_content); 72 | } 73 | 74 | mxmlDelete(root); 75 | 76 | return s; 77 | } 78 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | compiler: 4 | - gcc 5 | 6 | install: 7 | - sudo apt-get update 8 | - sudo apt-get install libapr1-dev libaprutil1-dev curl 9 | - wget --quiet http://www.msweet.org/files/project3/mxml-2.9.tar.gz 10 | - tar zxf mxml-2.9.tar.gz 11 | - cd mxml-2.9 12 | - ./configure && make && sudo make install 13 | - cd - 14 | - pip install --user cpp-coveralls 15 | 16 | script: 17 | - cmake -DCMAKE_BUILD_TYPE=Coverage . 18 | - make 19 | - ./build/Coverage/bin/oss_c_sdk_test 20 | 21 | after_success: 22 | - coveralls --include src/ --gcov-options '\-lp' 23 | 24 | env: 25 | global: 26 | - secure: kvjsFXirn2+Nys0TO0eViDHTlhz0ow5AuWuQeEzJAJnLbJfqupWng0o3i4vGF7bPpxWgbrIFJro/Pwk15F1gvUGaKjXbPWn5hae3G3ZqDwdNkDYy8Hs8VnjvqlaZ4dbpqDQOFA7+49jUuzVPdHFWJgLEleE53RADfuESN/rd0Uo6C1mZEEmyEhmj2pyHSKr08UWLbbuoLuVeaF1rfLxLRAU/Ki0S1AnnFirJcsbMSICexwQ96G+bdQTdqHass6JfQfOYklnKVSrMbk/0MuV5LmeQ3A1j1AF3iRzZ4KT4FmNXwk0hoocz+la8M3B7zaUu2wuea8LV5mZ6G5bN5p2fYHXlpZaoxstMl3HUwiQH5ETX0W6bzB1rjWl2CteKR3xt2wW1qj5XDvjqBUrPNV0yibpfMdkVfLnvic16+0qZua2cjsn93d0AyNnS6cFCGAH3PGI7+3Mmg4T1S43z9XjXjHmOCT0EQ/kfGI0m+3p8TYqqQMandWbphpXZYPdHBeSv4tMMFn1p7bjwn5fxvUKCou/tvef7qD3OYjectiEzTou7Ttxz6gThiDekIf8Pbeuzq5mgnSDXr+8DTpHzKltsQBLyhezlBL9P5PW6GH3xp+/4yFHPOnsOhK7qLkiJ6CQ9JPq2noeAAh+cgKiSoZibaWj3ht2p1LynR/Kr8XQfZfQ= 27 | - secure: pLU+jHSLKimMSX0I3sL9To7sg+hO7vEplZhCL9OPUj8vTVmdLCRnbNiTAUaUrSA0/O55lxeleBfyi6joPY5IOgCRASExhFxfsidKjskb77bKl1/izt4EH41sahlcrbmpgPRdXORyOzCN9HkuWvrR8FZsTwnBpHJ3+IxsxKURGlY8NYN50sscqM+KvctUvXf+j/y0gZK42F78bLD3WRr1Fiph9UOYOUPvnQe69tOUwrKil5u8Ho+JeQCpuXsiDJkYz232WSgKOw326AIjo99VLvw1Q3HTdU8ztsarcswjLTSMpHpPT6vxNKVd0WUi6zmZpO/CLZvqtPxtPizT54OurDB7ClUJ0KJyFRgOaaRofbKDi8xWXATIYfI92x0IHIq/4aeufc3N4zQDgjdRrp4silS56IxTi+OM/T6opIg258j7lrEUP3nz+DBOqCSYBL1pIfhJDeoWSFYE2Ehc7paVCFkoEp41lv1sgBX1At0dM7lobIlsMX2zmQPszLQTgaj8mu/5u7/tFMFSw4TWydI+el3xJVlq4ad2DpYP/yRPEcUkq64/qPZP1dSfxlwBzEOCk4zoAQHev3php32O5vDyLcV3R1Zvyr0Y1/suPMXeUEU6kvS26I9jSpwB/E3i+6HhfcqcnmaGxqr1pRw/dhedGAAayKZEqDcEpTdXf9D6BcE= 28 | - secure: wFXioHVdO0bP4N8o/q+y76K65vyls3CIzM3I71ZN1+Ayl01Z0c1WxL+84LlhHjUetMzFG2X10zdnMmuthUz9mkIRMxBxrbp6O2VzrniMkkFjzkK0P2obuLn3N0DfCT072XxvSt5l6aymB0+8Jv77d/nLxslGMIEkJWW9qgZQuTABRjQxCNwJ6Yo2I85kH6nXvdBsYvGCAkM+N1bZP7HvncvQgncZq+ImgOG7Hj21mdVCRF+qSw4o4YOBd6JELUtntpqRpp9gx52H2CgvTUYIb3gppmm392cAlNrUZirINCVXfJdfnq1pbHFJW5L9jdkJxq1L4SIOpZZX3yf5+pDqVHXXVh4hyW1oUBQejTzX76GD8Xwh51NzGXATkhEuGgchvQeb6ul7Q/+S6JzdWlrkQwc4cIZS3fjdpAsXtPlaiEsoQja1zNWHlQvylF//5+r69TiYFTJ737YyckKv6iEhY92zWg0qBDaDQGQ7lM/kudb1WrDOAV7xaNMuY1ys7mXZmaiyq6sD03EkBrndJMtcu3Z2ofId4IOMOvLT0sWACtKP8R3ajo8oyGJAftcvi4w/2bz1OwJ010vVvPwrbmT16WFrSuzUrMXZwkjDHBT//PxjrY7OLl0js6xxrujjm1sc+ekSUOfnZFshT+4yRCAxcLrrmuclvLVSPAYHMQ6E4lA= 29 | - secure: WSTMesLCs2QMOzSkfNrMnYPUaWBRG+RFWGFWC1GvXaxz0rJxRdtFkWJ05mcmsOMBCPbBwzh9LWm1a7ssDcljnDHc/3nOuiyKc3AgZ8pxlVxJj0ujj/HIxB5GbcbEePzMvJcSPMq/QFYpfyWM/8qRo3I0PYpLQatq75tILSuHkmay9Ic96ixqNsjVCey/uOB3RZB68fzmxok+wVnpPe6y0wcL9uK7xKmrRc7pEMr8/9BjbtyBKOPbBgtV6ArJf4j3Wy9Di9ZOdkR8PLGtWaf8vEFat3NtvzXG/Ag9cCkbU/t4ZZuwmF5MiaWNpQeZt8pdvPh0WFnmhs9kZyq0vm0W3lDoJ5tBBSHmu+LdZSCnkHuGWvaaofpPKOSLE5MBVucKHLGurQj0wGY3Xw4Vc9m76YKGRcbJ6iWjcf+WOSLdcepagpN+aeGgG+yY60mCnNiEUPKCK7A8bZmF2GyMR3JgJSEQ1gjfI4iDi8PBZ9dMAWFDUqhixwCZQuVbsEcspXFVNFjjks/2aRG5RnAAIEhatz4ja2Koxv/ZhJn752sw4l3N6GNSjYlqZl5xA41Ycr6nDGqbB87xp+DiYeEzNmwFmpAnrA5Ur8ZFE9HEObGgCdouRLjyPjhLUS+QEeDangEth7bXlACBQxPMlJsjBrXuQxykT+TtqVexOWQtVe9nuJQ= 30 | -------------------------------------------------------------------------------- /src/aos_list.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_LIST_H 2 | #define LIBAOS_LIST_H 3 | 4 | #include 5 | 6 | // from kernel list 7 | typedef struct aos_list_s aos_list_t; 8 | 9 | struct aos_list_s { 10 | aos_list_t *next, *prev; 11 | }; 12 | 13 | #define AOS_LIST_HEAD_INIT(name) {&(name), &(name)} 14 | #define aos_list_init(ptr) do { \ 15 | (ptr)->next = (ptr); \ 16 | (ptr)->prev = (ptr); \ 17 | } while (0) 18 | 19 | static inline void __aos_list_add(aos_list_t *list, aos_list_t *prev, aos_list_t *next) 20 | { 21 | next->prev = list; 22 | list->next = next; 23 | list->prev = prev; 24 | prev->next = list; 25 | } 26 | 27 | // list head to add it before 28 | static inline void aos_list_add_tail(aos_list_t *list, aos_list_t *head) 29 | { 30 | __aos_list_add(list, head->prev, head); 31 | } 32 | 33 | static inline void __aos_list_del(aos_list_t *prev, aos_list_t *next) 34 | { 35 | next->prev = prev; 36 | prev->next = next; 37 | } 38 | 39 | // deletes entry from list 40 | static inline void aos_list_del(aos_list_t *entry) 41 | { 42 | __aos_list_del(entry->prev, entry->next); 43 | aos_list_init(entry); 44 | } 45 | 46 | // tests whether a list is empty 47 | static inline int aos_list_empty(const aos_list_t *head) 48 | { 49 | return (head->next == head); 50 | } 51 | 52 | // move list to new_list 53 | static inline void aos_list_movelist(aos_list_t *list, aos_list_t *new_list) 54 | { 55 | if (!aos_list_empty(list)) { 56 | new_list->prev = list->prev; 57 | new_list->next = list->next; 58 | new_list->prev->next = new_list; 59 | new_list->next->prev = new_list; 60 | aos_list_init(list); 61 | } else { 62 | aos_list_init(new_list); 63 | } 64 | } 65 | 66 | // get last 67 | #define aos_list_get_last(list, type, member) \ 68 | aos_list_empty(list) ? NULL : aos_list_entry((list)->prev, type, member) 69 | 70 | // get first 71 | #define aos_list_get_first(list, type, member) \ 72 | aos_list_empty(list) ? NULL : aos_list_entry((list)->next, type, member) 73 | 74 | #define aos_list_entry(ptr, type, member) ({ \ 75 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 76 | (type *)( (char *)__mptr - APR_OFFSETOF(type,member) );}) 77 | 78 | #define aos_list_for_each_entry(pos, head, member) \ 79 | for (pos = aos_list_entry((head)->next, typeof(*pos), member); \ 80 | &pos->member != (head); \ 81 | pos = aos_list_entry(pos->member.next, typeof(*pos), member)) 82 | 83 | #define aos_list_for_each_entry_reverse(pos, head, member) \ 84 | for (pos = aos_list_entry((head)->prev, typeof(*pos), member); \ 85 | &pos->member != (head); \ 86 | pos = aos_list_entry(pos->member.prev, typeof(*pos), member)) 87 | 88 | #define aos_list_for_each_entry_safe(pos, n, head, member) \ 89 | for (pos = aos_list_entry((head)->next, typeof(*pos), member), \ 90 | n = aos_list_entry(pos->member.next, typeof(*pos), member); \ 91 | &pos->member != (head); \ 92 | pos = n, n = aos_list_entry(n->member.next, typeof(*n), member)) 93 | 94 | #define aos_list_for_each_entry_safe_reverse(pos, n, head, member) \ 95 | for (pos = aos_list_entry((head)->prev, typeof(*pos), member), \ 96 | n = aos_list_entry(pos->member.prev, typeof(*pos), member); \ 97 | &pos->member != (head); \ 98 | pos = n, n = aos_list_entry(n->member.prev, typeof(*n), member)) 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /test/test_all.c: -------------------------------------------------------------------------------- 1 | #include "CuTest.h" 2 | #include "aos_log.h" 3 | #include "aos_http_io.h" 4 | #include "oss_config.h" 5 | 6 | extern CuSuite *test_xml(); 7 | extern CuSuite *test_util(); 8 | extern CuSuite *test_file(); 9 | extern CuSuite *test_transport(); 10 | extern CuSuite *test_oss_bucket(); 11 | extern CuSuite *test_oss_object(); 12 | extern CuSuite *test_oss_multipart(); 13 | extern CuSuite *test_oss_util(); 14 | extern CuSuite *test_oss_xml(); 15 | extern CuSuite *test_aos(); 16 | 17 | static const struct testlist { 18 | const char *testname; 19 | CuSuite *(*func)(void); 20 | } tests[] = { 21 | {"test_oss_bucket", test_oss_bucket}, 22 | {"test_oss_object", test_oss_object}, 23 | {"test_oss_multipart", test_oss_multipart}, 24 | {"test_aos", test_aos}, 25 | {"LastTest", NULL} 26 | }; 27 | 28 | int run_all_tests(int argc, char *argv[]) 29 | { 30 | int i; 31 | int exit_code; 32 | int list_provided = 0; 33 | CuSuite* suite = NULL; 34 | int j; 35 | int found; 36 | CuSuite *st = NULL; 37 | CuString *output = NULL; 38 | 39 | for (i = 1; i < argc; i++) { 40 | if (!strcmp(argv[i], "-v")) { 41 | continue; 42 | } 43 | if (!strcmp(argv[i], "-l")) { 44 | for (i = 0; tests[i].func != NULL; i++) { 45 | printf("%s\n", tests[i].testname); 46 | } 47 | exit(0); 48 | } 49 | if (argv[i][0] == '-') { 50 | fprintf(stderr, "invalid option: `%s'\n", argv[i]); 51 | exit(1); 52 | } 53 | list_provided = 1; 54 | } 55 | 56 | suite = CuSuiteNew(); 57 | 58 | if (!list_provided) { 59 | /* add everything */ 60 | for (i = 0; tests[i].func != NULL; i++) { 61 | st = tests[i].func(); 62 | CuSuiteAddSuite(suite, st); 63 | CuSuiteFree(st); 64 | } 65 | } else { 66 | /* add only the tests listed */ 67 | for (i = 1; i < argc; i++) { 68 | found = 0; 69 | if (argv[i][0] == '-') { 70 | continue; 71 | } 72 | for (j = 0; tests[j].func != NULL; j++) { 73 | if (!strcmp(argv[i], tests[j].testname)) { 74 | CuSuiteAddSuite(suite, tests[j].func()); 75 | found = 1; 76 | } 77 | } 78 | if (!found) { 79 | fprintf(stderr, "invalid test name: `%s'\n", argv[i]); 80 | exit(1); 81 | } 82 | } 83 | } 84 | 85 | output = CuStringNew(); 86 | CuSuiteRun(suite); 87 | CuSuiteSummary(suite, output); 88 | CuSuiteDetails(suite, output); 89 | printf("%s\n", output->buffer); 90 | 91 | exit_code = suite->failCount > 0 ? 1 : 0; 92 | 93 | CuSuiteFreeDeep(suite); 94 | CuStringFree(output); 95 | 96 | return exit_code; 97 | } 98 | 99 | int main(int argc, char *argv[]) 100 | { 101 | TEST_OSS_ENDPOINT = TEST_OSS_ENDPOINT != NULL ? 102 | TEST_OSS_ENDPOINT : getenv("OSS_TEST_ENDPOINT"); 103 | TEST_ACCESS_KEY_ID = TEST_ACCESS_KEY_ID != NULL ? 104 | TEST_ACCESS_KEY_ID : getenv("OSS_TEST_ACCESS_KEY_ID"); 105 | TEST_ACCESS_KEY_SECRET = TEST_ACCESS_KEY_SECRET != NULL ? 106 | TEST_ACCESS_KEY_SECRET : getenv("OSS_TEST_ACCESS_KEY_SECRET"); 107 | TEST_BUCKET_NAME = TEST_BUCKET_NAME != NULL ? 108 | TEST_BUCKET_NAME : getenv("OSS_TEST_BUCKET"); 109 | 110 | int exit_code; 111 | if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { 112 | exit(1); 113 | } 114 | 115 | aos_log_set_level(AOS_LOG_OFF); 116 | exit_code = run_all_tests(argc, argv); 117 | 118 | //aos_http_io_deinitialize last 119 | aos_http_io_deinitialize(); 120 | 121 | return exit_code; 122 | } 123 | -------------------------------------------------------------------------------- /sample/oss_append_object_sample.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "aos_util.h" 3 | #include "aos_string.h" 4 | #include "aos_status.h" 5 | #include "oss_auth.h" 6 | #include "oss_util.h" 7 | #include "oss_api.h" 8 | #include "oss_config.h" 9 | #include "oss_sample_util.h" 10 | 11 | void append_object_from_buffer() 12 | { 13 | aos_pool_t *p = NULL; 14 | aos_string_t bucket; 15 | aos_string_t object; 16 | char *str = "test oss c sdk"; 17 | aos_status_t *s = NULL; 18 | int is_cname = 0; 19 | int64_t position = 0; 20 | aos_table_t *headers1 = NULL; 21 | aos_table_t *headers2 = NULL; 22 | aos_table_t *resp_headers = NULL; 23 | oss_request_options_t *options = NULL; 24 | aos_list_t buffer; 25 | aos_buf_t *content = NULL; 26 | char *next_append_position = NULL; 27 | 28 | aos_pool_create(&p, NULL); 29 | options = oss_request_options_create(p); 30 | init_sample_request_options(options, is_cname); 31 | headers1 = aos_table_make(p, 0); 32 | aos_str_set(&bucket, BUCKET_NAME); 33 | aos_str_set(&object, OBJECT_NAME); 34 | s = oss_head_object(options, &bucket, &object, headers1, &resp_headers); 35 | if (NULL != s && s->code == 200) { 36 | next_append_position = (char*)(apr_table_get(resp_headers, 37 | "x-oss-next-append-position")); 38 | position = atoi(next_append_position); 39 | } 40 | 41 | headers2 = aos_table_make(p, 0); 42 | aos_list_init(&buffer); 43 | content = aos_buf_pack(p, str, strlen(str)); 44 | aos_list_add_tail(&content->node, &buffer); 45 | s = oss_append_object_from_buffer(options, &bucket, &object, 46 | position, &buffer, headers2, &resp_headers); 47 | 48 | if (NULL != s && 2 == s->code / 100) 49 | { 50 | printf("append object from buffer succeeded\n"); 51 | } else { 52 | printf("append object from buffer failed\n"); 53 | } 54 | 55 | aos_pool_destroy(p); 56 | } 57 | 58 | void append_object_from_file() 59 | { 60 | aos_pool_t *p = NULL; 61 | aos_string_t bucket; 62 | aos_string_t object; 63 | int is_cname = 0; 64 | aos_table_t *headers1 = NULL; 65 | aos_table_t *headers2 = NULL; 66 | aos_table_t *resp_headers = NULL; 67 | oss_request_options_t *options = NULL; 68 | char *filename = __FILE__; 69 | aos_status_t *s = NULL; 70 | aos_string_t file; 71 | int64_t position = 0; 72 | char *next_append_position = NULL; 73 | 74 | aos_pool_create(&p, NULL); 75 | options = oss_request_options_create(p); 76 | init_sample_request_options(options, is_cname); 77 | headers1 = aos_table_make(options->pool, 0); 78 | headers2 = aos_table_make(options->pool, 0); 79 | aos_str_set(&bucket, BUCKET_NAME); 80 | aos_str_set(&object, OBJECT_NAME); 81 | aos_str_set(&file, filename); 82 | 83 | s = oss_head_object(options, &bucket, &object, headers1, &resp_headers); 84 | if(NULL != s && 2 == s->code / 100) { 85 | next_append_position = (char*)(apr_table_get(resp_headers, 86 | "x-oss-next-append-position")); 87 | position = atoi(next_append_position); 88 | } 89 | 90 | s = oss_append_object_from_file(options, &bucket, &object, 91 | position, &file, headers2, &resp_headers); 92 | 93 | if (NULL != s && 2 == s->code / 100) { 94 | printf("append object from file succeeded\n"); 95 | } else { 96 | printf("append object from file failed\n"); 97 | } 98 | 99 | aos_pool_destroy(p); 100 | } 101 | 102 | int main(int argc, char *argv[]) 103 | { 104 | if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { 105 | exit(1); 106 | } 107 | 108 | append_object_from_buffer(); 109 | append_object_from_file(); 110 | 111 | aos_http_io_deinitialize(); 112 | 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Aliyun OSS SDK for C 2 | 3 | [![GitHub version](https://badge.fury.io/gh/aliyun%2Faliyun-oss-c-sdk.svg)](https://badge.fury.io/gh/aliyun%2Faliyun-oss-c-sdk) 4 | [![Build Status](https://travis-ci.org/aliyun/aliyun-oss-c-sdk.svg?branch=master)](https://travis-ci.org/aliyun/aliyun-oss-c-sdk) 5 | [![Coverage Status](https://coveralls.io/repos/github/aliyun/aliyun-oss-c-sdk/badge.svg?branch=master)](https://coveralls.io/github/aliyun/aliyun-oss-c-sdk?branch=master) 6 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE) 7 | 8 | ## 关于 9 | 阿里云对象存储(Object Storage Service,简称OSS),是阿里云对外提供的海量、安全、低成本、高可靠的云存储服务。用户可以通过调用API,在任何应用、任何时间、任何地点上传和下载数据,也可以通过用户Web控制台对数据进行简单的管理。OSS适合存放任意文件类型,适合各种网站、开发企业及开发者使用。OSS C SDK提供了一系列接口方便用户使用OSS。 10 | 11 | ## 版本 12 | - 当前版本:2.0.0 13 | 14 | ## 安装方法 15 | ### 环境依赖 16 | OSS C SDK使用curl进行网络操作,无论是作为客户端还是服务器端,都需要依赖curl。 17 | 另外,OSS C SDK使用apr/apr-util库解决内存管理以及跨平台问题,使用minixml库解析请求返回的xml, 18 | OSS C SDK并没有带上这几个外部库,您需要确认这些库已经安装,并且将它们的头文件目录和库文件目录都加入到了项目中。 19 | 20 | #### 第三方库下载以及安装 21 | 22 | ##### libcurl (建议 7.32.0 及以上版本) 23 | 24 | 请从[这里](http://curl.haxx.se/download.html)下载,并参考[libcurl 安装指南](http://curl.haxx.se/docs/install.html)安装。典型的安装方式如下: 25 | ```shell 26 | ./configure 27 | make 28 | make install 29 | ``` 30 | 31 | 注意: 32 | - 执行./configure时默认是配置安装目录为/usr/local/,如果需要指定安装目录,请使用 ./configure --prefix=/your/install/path/ 33 | 34 | ##### apr (建议 1.5.2 及以上版本) 35 | 36 | 请从[这里](https://apr.apache.org/download.cgi)下载,典型的安装方式如下: 37 | ```shell 38 | ./configure 39 | make 40 | make install 41 | ``` 42 | 43 | 注意: 44 | - 执行./configure时默认是配置安装目录为/usr/local/,如果需要指定安装目录,请使用 ./configure --prefix=/your/install/path/ 45 | 46 | ##### apr-util (建议 1.5.4 及以上版本) 47 | 48 | 请从[这里](https://apr.apache.org/download.cgi)下载,安装时需要注意指定--with-apr选项,典型的安装方式如下: 49 | ```shell 50 | ./configure --with-apr=/your/apr/install/path 51 | make 52 | make install 53 | ``` 54 | 55 | 注意: 56 | - 执行./configure时默认是配置安装目录为/usr/local/,如果需要指定安装目录,请使用 ./configure --prefix=/your/install/path/ 57 | - 需要通过--with-apr指定apr安装目录,如果apr安装到系统目录下需要指定--with-apr=/usr/local/apr/ 58 | 59 | ##### minixml (建议 2.8 及以上版本) 60 | 61 | 请从[这里](http://www.msweet.org/downloads.php?L+Z3)下载,典型的安装方式如下: 62 | ```shell 63 | ./configure 64 | make 65 | make install 66 | ``` 67 | 68 | 69 | 注意: 70 | - 执行./configure时默认是配置安装目录为/usr/local/,如果需要指定安装目录,请使用 ./configure --prefix=/your/install/path/ 71 | 72 | ##### CMake (建议2.6.0及以上版本) 73 | 74 | 请从[这里](https://cmake.org/download)下载,典型的安装方式如下: 75 | ```shell 76 | ./configure 77 | make 78 | make install 79 | ``` 80 | 81 | 注意: 82 | - 执行./configure时默认是配置安装目录为/usr/local/,如果需要指定安装目录,请使用 ./configure --prefix=/your/install/path/ 83 | 84 | #### OSS C SDK的安装 85 | 86 | 安装时请在cmake命令中指定第三方库头文件以及库文件的路径,典型的编译命令如下: 87 | ```shell 88 | cmake . 89 | make 90 | make install 91 | ``` 92 | 93 | 注意: 94 | - 执行cmake . 时默认会到/usr/local/下面去寻找curl,apr,apr-util,mxml的头文件和库文件。 95 | - 默认编译是Debug类型,可以指定以下几种编译类型: Debug, Release, RelWithDebInfo和MinSizeRel,如果要使用release类型编译,则执行cmake . -DCMAKE_BUILD_TYPE=Release 96 | - 如果您在安装curl,apr,apr-util,mxml时指定了安装目录,则需要在执行cmake时指定这些库的路径,比如: 97 | ```shell 98 | cmake . -DCURL_INCLUDE_DIR=/usr/local/include/curl/ -DCURL_LIBRARY=/usr/local/lib/libcurl.a -DAPR_INCLUDE_DIR=/usr/local/include/apr-1/ -DAPR_LIBRARY=/usr/local/lib/libapr-1.a -DAPR_UTIL_INCLUDE_DIR=/usr/local/apr/include/apr-1 -DAPR_UTIL_LIBRARY=/usr/local/apr/lib/libaprutil-1.a -DMINIXML_INCLUDE_DIR=/usr/local/include -DMINIXML_LIBRARY=/usr/local/lib/libmxml.a 99 | ``` 100 | - 如果要指定安装目录,则需要在cmake时增加: -DCMAKE_INSTALL_PREFIX=/your/install/path/usr/local/ 101 | 102 | ## 联系我们 103 | - [阿里云OSS官方网站](http://oss.aliyun.com) 104 | - [阿里云OSS官方论坛](http://bbs.aliyun.com) 105 | - [阿里云OSS官方文档中心](http://www.aliyun.com/product/oss#Docs) 106 | - 阿里云官方技术支持:[提交工单](https://workorder.console.aliyun.com/#/ticket/createIndex) 107 | -------------------------------------------------------------------------------- /src/aos_define.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_DEFINE_H 2 | #define LIBAOS_DEFINE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef __cplusplus 21 | # define AOS_CPP_START extern "C" { 22 | # define AOS_CPP_END } 23 | #else 24 | # define AOS_CPP_START 25 | # define AOS_CPP_END 26 | #endif 27 | 28 | typedef enum { 29 | HTTP_GET, 30 | HTTP_HEAD, 31 | HTTP_PUT, 32 | HTTP_POST, 33 | HTTP_DELETE 34 | } http_method_e; 35 | 36 | typedef enum { 37 | AOSE_OK = 0, 38 | AOSE_OUT_MEMORY = -1000, 39 | AOSE_OVER_MEMORY = -999, 40 | AOSE_FAILED_CONNECT = -998, 41 | AOSE_ABORT_CALLBACK = -997, 42 | AOSE_INTERNAL_ERROR = -996, 43 | AOSE_REQUEST_TIMEOUT = -995, 44 | AOSE_INVALID_ARGUMENT = -994, 45 | AOSE_INVALID_OPERATION = -993, 46 | AOSE_CONNECTION_FAILED = -992, 47 | AOSE_FAILED_INITIALIZE = -991, 48 | AOSE_NAME_LOOKUP_ERROR = -990, 49 | AOSE_FAILED_VERIFICATION = -989, 50 | AOSE_WRITE_BODY_ERROR = -988, 51 | AOSE_READ_BODY_ERROR = -987, 52 | AOSE_SERVICE_ERROR = -986, 53 | AOSE_OPEN_FILE_ERROR = -985, 54 | AOSE_FILE_SEEK_ERROR = -984, 55 | AOSE_FILE_INFO_ERROR = -983, 56 | AOSE_FILE_READ_ERROR = -982, 57 | AOSE_FILE_WRITE_ERROR = -981, 58 | AOSE_XML_PARSE_ERROR = -980, 59 | AOSE_UTF8_ENCODE_ERROR = -979, 60 | AOSE_UNKNOWN_ERROR = -978 61 | } aos_error_code_e; 62 | 63 | typedef apr_pool_t aos_pool_t; 64 | typedef apr_table_t aos_table_t; 65 | typedef apr_table_entry_t aos_table_entry_t; 66 | typedef apr_array_header_t aos_array_header_t; 67 | 68 | #define aos_table_elts(t) apr_table_elts(t) 69 | #define aos_is_empty_table(t) apr_is_empty_table(t) 70 | #define aos_table_make(p, n) apr_table_make(p, n) 71 | #define aos_table_add_int(t, key, value) do { \ 72 | char value_str[64]; \ 73 | snprintf(value_str, sizeof(value_str), "%d", value);\ 74 | apr_table_add(t, key, value_str); \ 75 | } while(0) 76 | 77 | #define aos_table_add_int64(t, key, value) do { \ 78 | char value_str[64]; \ 79 | snprintf(value_str, sizeof(value_str), "%" APR_INT64_T_FMT, value);\ 80 | apr_table_add(t, key, value_str); \ 81 | } while(0) 82 | 83 | #define aos_table_set_int64(t, key, value) do { \ 84 | char value_str[64]; \ 85 | snprintf(value_str, sizeof(value_str), "%" APR_INT64_T_FMT, value);\ 86 | apr_table_set(t, key, value_str); \ 87 | } while(0) 88 | 89 | #define aos_pool_create(n, p) apr_pool_create(n, p) 90 | #define aos_pool_destroy(p) apr_pool_destroy(p) 91 | #define aos_palloc(p, s) apr_palloc(p, s) 92 | #define aos_pcalloc(p, s) apr_pcalloc(p, s) 93 | 94 | #define AOS_INIT_WINSOCK 1 95 | #define AOS_MD5_STRING_LEN 32 96 | #define AOS_MAX_URI_LEN 2048 97 | #define AOS_MAX_HEADER_LEN 4096 98 | #define AOS_MAX_QUERY_ARG_LEN 1024 99 | #define AOS_MAX_GMT_TIME_LEN 128 100 | 101 | #define AOS_CONNECT_TIMEOUT 10 102 | #define AOS_DNS_CACHE_TIMOUT 60 103 | #define AOS_MIN_SPEED_LIMIT 1024 104 | #define AOS_MIN_SPEED_TIME 15 105 | #define AOS_MAX_MEMORY_SIZE 1024*1024*1024L; 106 | 107 | #define AOS_REQUEST_STACK_SIZE 32 108 | 109 | #define aos_abs(value) (((value) >= 0) ? (value) : - (value)) 110 | #define aos_max(val1, val2) (((val1) < (val2)) ? (val2) : (val1)) 111 | #define aos_min(val1, val2) (((val1) > (val2)) ? (val2) : (val1)) 112 | 113 | #define LF (char) 10 114 | #define CR (char) 13 115 | #define CRLF "\x0d\x0a" 116 | 117 | #define AOS_VERSION "2.0.0" 118 | #define AOS_VER "aliyun-sdk-c/" AOS_VERSION 119 | 120 | #define AOS_HTTP_PREFIX "http://" 121 | #define AOS_HTTPS_PREFIX "https://" 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /src/aos_transport.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBAOS_TRANSPORT_H 2 | #define LIBAOS_TRANSPORT_H 3 | 4 | #include "aos_define.h" 5 | #include "aos_buf.h" 6 | 7 | AOS_CPP_START 8 | 9 | typedef struct aos_http_request_s aos_http_request_t; 10 | typedef struct aos_http_response_s aos_http_response_t; 11 | typedef struct aos_http_transport_s aos_http_transport_t; 12 | typedef struct aos_http_controller_s aos_http_controller_t; 13 | 14 | typedef struct aos_http_request_options_s aos_http_request_options_t; 15 | typedef struct aos_http_transport_options_s aos_http_transport_options_t; 16 | typedef struct aos_curl_http_transport_s aos_curl_http_transport_t; 17 | 18 | typedef int (*aos_read_http_body_pt)(aos_http_request_t *req, char *buffer, int len); 19 | typedef int (*aos_write_http_body_pt)(aos_http_response_t *resp, const char *buffer, int len); 20 | 21 | void aos_curl_response_headers_parse(aos_pool_t *p, aos_table_t *headers, char *buffer, int len); 22 | aos_http_transport_t *aos_curl_http_transport_create(aos_pool_t *p); 23 | int aos_curl_http_transport_perform(aos_http_transport_t *t); 24 | 25 | struct aos_http_request_options_s { 26 | int speed_limit; 27 | int speed_time; 28 | int dns_cache_timeout; 29 | int connect_timeout; 30 | int64_t max_memory_size; 31 | }; 32 | 33 | struct aos_http_transport_options_s { 34 | char *user_agent; 35 | char *cacerts_path; 36 | uint32_t ssl_verification_disabled:1; 37 | }; 38 | 39 | #define AOS_HTTP_BASE_CONTROLLER_DEFINE \ 40 | aos_http_request_options_t *options; \ 41 | aos_pool_t *pool; \ 42 | int64_t start_time; \ 43 | int64_t first_byte_time; \ 44 | int64_t finish_time; \ 45 | uint32_t owner:1; \ 46 | void *user_data; 47 | 48 | struct aos_http_controller_s { 49 | AOS_HTTP_BASE_CONTROLLER_DEFINE 50 | }; 51 | 52 | typedef struct aos_http_controller_ex_s { 53 | AOS_HTTP_BASE_CONTROLLER_DEFINE 54 | // private 55 | int error_code; 56 | char *reason; // can't modify 57 | } aos_http_controller_ex_t; 58 | 59 | typedef enum { 60 | BODY_IN_MEMORY = 0, 61 | BODY_IN_FILE, 62 | BODY_IN_CALLBACK 63 | } aos_http_body_type_e; 64 | 65 | struct aos_http_request_s { 66 | char *host; 67 | char *proto; 68 | char *signed_url; 69 | 70 | http_method_e method; 71 | char *uri; 72 | char *resource; 73 | aos_table_t *headers; 74 | aos_table_t *query_params; 75 | 76 | aos_list_t body; 77 | int64_t body_len; 78 | char *file_path; 79 | aos_file_buf_t *file_buf; 80 | 81 | aos_pool_t *pool; 82 | void *user_data; 83 | aos_read_http_body_pt read_body; 84 | 85 | aos_http_body_type_e type; 86 | }; 87 | 88 | struct aos_http_response_s { 89 | int status; 90 | aos_table_t *headers; 91 | 92 | aos_list_t body; 93 | int64_t body_len; 94 | char *file_path; 95 | aos_file_buf_t* file_buf; 96 | int64_t content_length; 97 | 98 | aos_pool_t *pool; 99 | void *user_data; 100 | aos_write_http_body_pt write_body; 101 | 102 | aos_http_body_type_e type; 103 | }; 104 | 105 | typedef enum { 106 | TRANS_STATE_INIT, 107 | TRANS_STATE_HEADER, 108 | TRANS_STATE_BODY_IN, 109 | TRANS_STATE_BODY_OUT, 110 | TRANS_STATE_ABORT, 111 | TRANS_STATE_DONE 112 | } aos_transport_state_e; 113 | 114 | #define AOS_HTTP_BASE_TRANSPORT_DEFINE \ 115 | aos_http_request_t *req; \ 116 | aos_http_response_t *resp; \ 117 | aos_pool_t *pool; \ 118 | aos_transport_state_e state; \ 119 | aos_array_header_t *cleanup; \ 120 | aos_http_transport_options_t *options; \ 121 | aos_http_controller_ex_t *controller; 122 | 123 | struct aos_http_transport_s { 124 | AOS_HTTP_BASE_TRANSPORT_DEFINE 125 | }; 126 | 127 | struct aos_curl_http_transport_s { 128 | AOS_HTTP_BASE_TRANSPORT_DEFINE 129 | CURL *curl; 130 | char *url; 131 | struct curl_slist *headers; 132 | curl_read_callback header_callback; 133 | curl_read_callback read_callback; 134 | curl_write_callback write_callback; 135 | }; 136 | 137 | AOS_CPP_END 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT(oss_c_sdk) 2 | 3 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 4 | 5 | set(CMAKE_VERSION 2.0.0) 6 | 7 | # default C / CXX flags 8 | set(CMAKE_C_FLAGS " -g -ggdb -O0 -Werror -fpic -fPIC -D_LARGEFILE64_SOURC") 9 | set(CMAKE_CXX_FLAGS " -g -ggdb -O0 -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE") 10 | 11 | set(CMAKE_C_FLAGS_DEBUG " -g -ggdb -O0 -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE") 12 | set(CMAKE_CXX_FLAGS_DEBUG " -g -ggdb -O0 -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE") 13 | 14 | set(CMAKE_C_FLAGS_RELEASE " -O3 -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE") 15 | set(CMAKE_CXX_FLAGS_RELEASE " -O3 -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE") 16 | 17 | set(CMAKE_C_FLAGS_MINSIZEREF " -Os -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE") 18 | set(CMAKE_CXX_FLAGS_MINSIZEREF " -Os -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE") 19 | 20 | set(CMAKE_C_FLAGS_RELWITHDEBINFO " -O2 -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE") 21 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO " -O2 -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE") 22 | 23 | set(CMAKE_C_FLAGS_COVERAGE " ${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage") 24 | set(CMAKE_CXX_FLAGS_COVERAGE " ${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverag") 25 | 26 | set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/build/${CMAKE_BUILD_TYPE}/lib) 27 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/build/${CMAKE_BUILD_TYPE}/bin) 28 | set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1) 29 | set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1) 30 | 31 | FIND_PROGRAM(APR_CONFIG_BIN NAMES apr-config apr-1-config PATHS /usr/bin /usr/local/bin /usr/local/apr/bin/) 32 | FIND_PROGRAM(APU_CONFIG_BIN NAMES apu-config apu-1-config PATHS /usr/bin /usr/local/bin /usr/local/apr/bin/) 33 | 34 | IF (APR_CONFIG_BIN) 35 | EXECUTE_PROCESS( 36 | COMMAND ${APR_CONFIG_BIN} --includedir 37 | OUTPUT_VARIABLE APR_INCLUDEDIRS 38 | OUTPUT_STRIP_TRAILING_WHITESPACE 39 | ) 40 | EXECUTE_PROCESS( 41 | COMMAND ${APR_CONFIG_BIN} --cflags 42 | OUTPUT_VARIABLE APR_C_FLAGS 43 | OUTPUT_STRIP_TRAILING_WHITESPACE 44 | ) 45 | EXECUTE_PROCESS( 46 | COMMAND ${APR_CONFIG_BIN} --link-ld 47 | OUTPUT_VARIABLE APR_LIBRARIES 48 | OUTPUT_STRIP_TRAILING_WHITESPACE 49 | ) 50 | ELSE() 51 | MESSAGE(FATAL_ERROR "Could not find apr-config/apr-1-config") 52 | ENDIF() 53 | 54 | IF (APU_CONFIG_BIN) 55 | EXECUTE_PROCESS( 56 | COMMAND ${APU_CONFIG_BIN} --includedir 57 | OUTPUT_VARIABLE APU_INCLUDEDIRS 58 | OUTPUT_STRIP_TRAILING_WHITESPACE 59 | ) 60 | EXECUTE_PROCESS( 61 | COMMAND ${APU_CONFIG_BIN} --cflags 62 | OUTPUT_VARIABLE APU_C_FLAGS 63 | OUTPUT_STRIP_TRAILING_WHITESPACE 64 | ) 65 | EXECUTE_PROCESS( 66 | COMMAND ${APU_CONFIG_BIN} --link-ld 67 | OUTPUT_VARIABLE APU_LIBRARIES 68 | OUTPUT_STRIP_TRAILING_WHITESPACE 69 | ) 70 | ELSE() 71 | MESSAGE(FATAL_ERROR "Could not find apu-config/apu-1-config") 72 | ENDIF() 73 | 74 | #curl-config 75 | FIND_PROGRAM(CURL_CONFIG_BIN NAMES curl-config) 76 | 77 | IF (CURL_CONFIG_BIN) 78 | EXECUTE_PROCESS( 79 | COMMAND ${CURL_CONFIG_BIN} --libs 80 | OUTPUT_VARIABLE CURL_LIBRARIES 81 | OUTPUT_STRIP_TRAILING_WHITESPACE 82 | ) 83 | ELSE() 84 | MESSAGE(FATAL_ERROR "Could not find curl-config") 85 | ENDIF() 86 | 87 | # Compile and link lib_oss_c_sdk 88 | include_directories(${APR_INCLUDEDIRS}) 89 | include_directories(${APU_INCLUDEDIRS}) 90 | 91 | aux_source_directory(src SRC_LIST) 92 | 93 | add_library(${CMAKE_PROJECT_NAME} SHARED ${SRC_LIST}) 94 | add_library(${CMAKE_PROJECT_NAME}_static STATIC ${SRC_LIST}) 95 | 96 | set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES VERSION ${CMAKE_VERSION} SOVERSION ${CMAKE_VERSION}) 97 | 98 | INSTALL(TARGETS ${CMAKE_PROJECT_NAME} LIBRARY DESTINATION lib) 99 | 100 | INSTALL(TARGETS ${CMAKE_PROJECT_NAME}_static ARCHIVE DESTINATION lib) 101 | 102 | INSTALL(FILES 103 | src/aos_buf.h 104 | src/aos_define.h 105 | src/aos_fstack.h 106 | src/aos_http_io.h 107 | src/aos_list.h 108 | src/aos_log.h 109 | src/aos_status.h 110 | src/aos_string.h 111 | src/aos_transport.h 112 | src/aos_util.h 113 | src/oss_api.h 114 | src/oss_auth.h 115 | src/oss_define.h 116 | src/oss_util.h 117 | src/oss_xml.h 118 | DESTINATION include/oss_c_sdk) 119 | 120 | add_subdirectory(sample) 121 | add_subdirectory(test) 122 | -------------------------------------------------------------------------------- /src/oss_xml.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBOSS_XML_H 2 | #define LIBOSS_XML_H 3 | 4 | #include 5 | #include "aos_string.h" 6 | #include "aos_transport.h" 7 | #include "aos_status.h" 8 | #include "oss_define.h" 9 | 10 | OSS_CPP_START 11 | 12 | /** 13 | * @brief functions for xml body parse 14 | **/ 15 | int get_xmldoc(aos_list_t *bc, mxml_node_t **root); 16 | char *get_xmlnode_value(aos_pool_t *p, mxml_node_t * root, const char *xml_path); 17 | 18 | /** 19 | * @brief build xml body for complete_multipart_upload 20 | **/ 21 | char *build_complete_multipart_upload_xml(aos_pool_t *p, aos_list_t *bc); 22 | 23 | /** 24 | * @brief build body for complete multipart upload 25 | **/ 26 | void build_complete_multipart_upload_body(aos_pool_t *p, aos_list_t *part_list, aos_list_t *body); 27 | 28 | /** 29 | * @brief build xml body for put lifecycle 30 | **/ 31 | char *build_lifecycle_xml(aos_pool_t *p, aos_list_t *lifecycle_rule_list); 32 | 33 | /** 34 | * @brief build body for put lifecycle 35 | **/ 36 | void build_lifecycle_body(aos_pool_t *p, aos_list_t *lifecycle_rule_list, aos_list_t *body); 37 | 38 | /** 39 | * @brief build xml body for delete objects 40 | **/ 41 | char *build_objects_xml(aos_pool_t *p, aos_list_t *object_list, const char *quiet); 42 | 43 | /** 44 | * @brief build body for delete objects 45 | **/ 46 | void build_delete_objects_body(aos_pool_t *p, aos_list_t *object_list, int is_quiet, 47 | aos_list_t *body); 48 | 49 | /** 50 | * @bried pares acl from xml body for get_bucket_acl 51 | **/ 52 | int oss_acl_parse_from_body(aos_pool_t *p, aos_list_t *bc, aos_string_t *oss_acl); 53 | 54 | /** 55 | * @brief parse upload_id from xml body for init multipart upload 56 | **/ 57 | int oss_upload_id_parse_from_body(aos_pool_t *p, aos_list_t *bc, aos_string_t *upload_id); 58 | 59 | /** 60 | * @brief parse objects from xml body for list objects 61 | **/ 62 | void oss_list_objects_owner_parse(aos_pool_t *p, mxml_node_t *xml_node, oss_list_object_content_t *content); 63 | void oss_list_objects_content_parse(aos_pool_t *p, mxml_node_t *xml_node, oss_list_object_content_t *content); 64 | void oss_list_objects_contents_parse(aos_pool_t *p, mxml_node_t *root, const char *xml_path, 65 | aos_list_t *object_list); 66 | void oss_list_objects_prefix_parse(aos_pool_t *p, mxml_node_t *root, 67 | oss_list_object_common_prefix_t *common_prefix); 68 | void oss_list_objects_common_prefix_parse(aos_pool_t *p, mxml_node_t *root, const char *xml_path, 69 | aos_list_t *common_prefix_list); 70 | int oss_list_objects_parse_from_body(aos_pool_t *p, aos_list_t *bc, aos_list_t *object_list, 71 | aos_list_t *common_prefix_list, aos_string_t *marker, int *truncated); 72 | 73 | /** 74 | * @brief parse parts from xml body for list upload part 75 | **/ 76 | void oss_list_parts_contents_parse(aos_pool_t *p, mxml_node_t *root, const char *xml_path, 77 | aos_list_t *part_list); 78 | void oss_list_parts_content_parse(aos_pool_t *p, mxml_node_t *xml_node, oss_list_part_content_t *content); 79 | int oss_list_parts_parse_from_body(aos_pool_t *p, aos_list_t *bc, aos_list_t *part_list, 80 | aos_string_t *part_number_marker, int *truncated); 81 | 82 | /** 83 | * @brief parse uploads from xml body for list multipart upload 84 | **/ 85 | void oss_list_multipart_uploads_contents_parse(aos_pool_t *p, mxml_node_t *root, const char *xml_path, 86 | aos_list_t *upload_list); 87 | void oss_list_multipart_uploads_content_parse(aos_pool_t *p, mxml_node_t *xml_node, 88 | oss_list_multipart_upload_content_t *content); 89 | int oss_list_multipart_uploads_parse_from_body(aos_pool_t *p, aos_list_t *bc, 90 | aos_list_t *upload_list, aos_string_t *key_marker, 91 | aos_string_t *upload_id_marker, int *truncated); 92 | 93 | /** 94 | * @brief parse lifecycle rules from xml body 95 | **/ 96 | void oss_lifecycle_rule_expire_parse(aos_pool_t *p, mxml_node_t *xml_node, 97 | oss_lifecycle_rule_content_t *content); 98 | void oss_lifecycle_rule_content_parse(aos_pool_t *p, mxml_node_t *xml_node, 99 | oss_lifecycle_rule_content_t *content); 100 | void oss_lifecycle_rule_contents_parse(aos_pool_t *p, mxml_node_t *root, const char *xml_path, 101 | aos_list_t *lifecycle_rule_list); 102 | int oss_lifecycle_rules_parse_from_body(aos_pool_t *p, aos_list_t *bc, aos_list_t *lifecycle_rule_list); 103 | 104 | /** 105 | * @brief parse delete objects contents from xml body 106 | **/ 107 | void oss_delete_objects_contents_parse(aos_pool_t *p, mxml_node_t *root, const char *xml_path, 108 | aos_list_t *object_list); 109 | void oss_object_key_parse(aos_pool_t *p, mxml_node_t * xml_node, oss_object_key_t *content); 110 | int oss_delete_objects_parse_from_body(aos_pool_t *p, aos_list_t *bc, aos_list_t *object_list); 111 | 112 | OSS_CPP_END 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /src/aos_buf.c: -------------------------------------------------------------------------------- 1 | #include "aos_buf.h" 2 | #include "aos_log.h" 3 | #include 4 | 5 | aos_buf_t *aos_create_buf(aos_pool_t *p, int size) 6 | { 7 | aos_buf_t* b; 8 | 9 | b = aos_palloc(p, sizeof(aos_buf_t) + size); 10 | if (b == NULL) { 11 | return NULL; 12 | } 13 | 14 | b->pos = (uint8_t *)b + sizeof(aos_buf_t); 15 | b->start = b->pos; 16 | b->last = b->start; 17 | b->end = b->last + size; 18 | aos_list_init(&b->node); 19 | 20 | return b; 21 | } 22 | 23 | aos_buf_t *aos_buf_pack(aos_pool_t *p, const void *data, int size) 24 | { 25 | aos_buf_t* b; 26 | 27 | b = aos_palloc(p, sizeof(aos_buf_t)); 28 | if (b == NULL) { 29 | return NULL; 30 | } 31 | 32 | b->pos = (uint8_t *)data; 33 | b->start = b->pos; 34 | b->last = b->start + size; 35 | b->end = b->last; 36 | aos_list_init(&b->node); 37 | 38 | return b; 39 | } 40 | 41 | int64_t aos_buf_list_len(aos_list_t *list) 42 | { 43 | aos_buf_t *b; 44 | int64_t len = 0; 45 | 46 | aos_list_for_each_entry(b, list, node) { 47 | len += aos_buf_size(b); 48 | } 49 | 50 | return len; 51 | } 52 | 53 | char *aos_buf_list_content(aos_pool_t *p, aos_list_t *list) 54 | { 55 | int64_t body_len; 56 | char *buf; 57 | int64_t pos = 0; 58 | int64_t size = 0; 59 | aos_buf_t *content; 60 | 61 | body_len = aos_buf_list_len(list); 62 | buf = aos_pcalloc(p, body_len + 1); 63 | buf[body_len] = '\0'; 64 | aos_list_for_each_entry(content, list, node) { 65 | size = aos_buf_size(content); 66 | memcpy(buf + pos, content->pos, size); 67 | pos += size; 68 | } 69 | return buf; 70 | } 71 | 72 | aos_file_buf_t *aos_create_file_buf(aos_pool_t *p) 73 | { 74 | return (aos_file_buf_t*)aos_pcalloc(p, sizeof(aos_file_buf_t)); 75 | } 76 | 77 | int aos_open_file_for_read(aos_pool_t *p, const char *path, aos_file_buf_t *fb) 78 | { 79 | int s; 80 | char buf[256]; 81 | apr_finfo_t finfo; 82 | 83 | if ((s = apr_file_open(&fb->file, path, APR_READ, APR_UREAD | APR_GREAD, p)) != APR_SUCCESS) { 84 | aos_error_log("apr_file_open failure, code:%d %s.", s, apr_strerror(s, buf, sizeof(buf))); 85 | assert(fb->file == NULL); 86 | return AOSE_OPEN_FILE_ERROR; 87 | } 88 | 89 | if ((s = apr_file_info_get(&finfo, APR_FINFO_NORM, fb->file)) != APR_SUCCESS) { 90 | apr_file_close(fb->file); 91 | aos_error_log("apr_file_open failure, code:%d %s.", s, apr_strerror(s, buf, sizeof(buf))); 92 | return AOSE_FILE_INFO_ERROR; 93 | } 94 | fb->file_pos = 0; 95 | fb->file_last = finfo.size; 96 | fb->owner = 1; 97 | 98 | return AOSE_OK; 99 | } 100 | 101 | int aos_open_file_for_all_read(aos_pool_t *p, const char *path, aos_file_buf_t *fb) 102 | { 103 | return aos_open_file_for_read(p, path, fb); 104 | } 105 | 106 | int aos_open_file_for_range_read(aos_pool_t *p, const char *path, 107 | int64_t file_pos, int64_t file_last, aos_file_buf_t *fb) 108 | { 109 | int s; 110 | 111 | s = aos_open_file_for_read(p, path, fb); 112 | if (s == AOSE_OK) { 113 | if (file_pos > fb->file_pos) { 114 | if (file_pos > fb->file_last) { 115 | aos_warn_log("read range beyond file size, read start:%" APR_INT64_T_FMT ", file size:%" APR_INT64_T_FMT "\n", 116 | file_pos, fb->file_last); 117 | file_pos = fb->file_last; 118 | } 119 | fb->file_pos = file_pos; 120 | } 121 | if (file_last < fb->file_last) { 122 | fb->file_last = file_last; 123 | } 124 | apr_file_seek(fb->file, APR_SET, (apr_off_t *)&fb->file_pos); 125 | } 126 | 127 | return s; 128 | } 129 | 130 | int aos_open_file_for_write(aos_pool_t *p, const char *path, aos_file_buf_t *fb) 131 | { 132 | int s; 133 | char buf[256]; 134 | 135 | if ((s = apr_file_open(&fb->file, path, APR_CREATE | APR_WRITE | APR_TRUNCATE, 136 | APR_UREAD | APR_UWRITE | APR_GREAD, p)) != APR_SUCCESS) { 137 | aos_error_log("apr_file_open failure, code:%d %s.", s, apr_strerror(s, buf, sizeof(buf))); 138 | assert(fb->file == NULL); 139 | return AOSE_OPEN_FILE_ERROR; 140 | } 141 | fb->owner = 1; 142 | 143 | return AOSE_OK; 144 | } 145 | 146 | void aos_buf_append_string(aos_pool_t *p, aos_buf_t *b, const char *str, int len) 147 | { 148 | int size; 149 | int nsize; 150 | int remain; 151 | char *buf; 152 | 153 | if (len <= 0) return; 154 | 155 | remain = b->end - b->last; 156 | 157 | if (remain > len + 128) { 158 | memcpy(b->last, str, len); 159 | b->last += len; 160 | } else { 161 | size = aos_buf_size(b); 162 | nsize = (size + len) * 2; 163 | buf = aos_palloc(p, nsize); 164 | memcpy(buf, b->pos, size); 165 | memcpy(buf+size, str, len); 166 | b->start = (uint8_t *)buf; 167 | b->end = (uint8_t *)buf + nsize; 168 | b->pos = (uint8_t *)buf; 169 | b->last = (uint8_t *)buf + size + len; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/oss_define.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBOSS_DEFINE_H 2 | #define LIBOSS_DEFINE_H 3 | 4 | #include "aos_string.h" 5 | #include "aos_list.h" 6 | #include "aos_transport.h" 7 | 8 | #ifdef __cplusplus 9 | # define OSS_CPP_START extern "C" { 10 | # define OSS_CPP_END } 11 | #else 12 | # define OSS_CPP_START 13 | # define OSS_CPP_END 14 | #endif 15 | 16 | #define aos_xml_error_status_set(STATUS, RES) do { \ 17 | aos_status_set(STATUS, RES, AOS_XML_PARSE_ERROR_CODE, NULL); \ 18 | } while(0) 19 | 20 | #define aos_file_error_status_set(STATUS, RES) do { \ 21 | aos_status_set(STATUS, RES, AOS_OPEN_FILE_ERROR_CODE, NULL); \ 22 | } while(0) 23 | 24 | extern const char OSS_CANNONICALIZED_HEADER_ACL[]; 25 | extern const char OSS_CANNONICALIZED_HEADER_SOURCE[]; 26 | extern const char OSS_CANNONICALIZED_HEADER_PREFIX[]; 27 | extern const char OSS_CANNONICALIZED_HEADER_DATE[]; 28 | extern const char OSS_CANNONICALIZED_HEADER_COPY_SOURCE[]; 29 | extern const char OSS_CONTENT_MD5[]; 30 | extern const char OSS_CONTENT_TYPE[]; 31 | extern const char OSS_DATE[]; 32 | extern const char OSS_AUTHORIZATION[]; 33 | extern const char OSS_ACCESSKEYID[]; 34 | extern const char OSS_EXPIRES[]; 35 | extern const char OSS_SIGNATURE[]; 36 | extern const char OSS_ACL[]; 37 | extern const char OSS_PREFIX[]; 38 | extern const char OSS_DELIMITER[]; 39 | extern const char OSS_MARKER[]; 40 | extern const char OSS_MAX_KEYS[]; 41 | extern const char OSS_UPLOADS[]; 42 | extern const char OSS_UPLOAD_ID[]; 43 | extern const char OSS_MAX_PARTS[]; 44 | extern const char OSS_KEY_MARKER[]; 45 | extern const char OSS_UPLOAD_ID_MARKER[]; 46 | extern const char OSS_MAX_UPLOADS[]; 47 | extern const char OSS_PARTNUMBER[]; 48 | extern const char OSS_PART_NUMBER_MARKER[]; 49 | extern const char OSS_APPEND[]; 50 | extern const char OSS_POSITION[]; 51 | extern const char OSS_MULTIPART_CONTENT_TYPE[]; 52 | extern const char OSS_COPY_SOURCE[]; 53 | extern const char OSS_COPY_SOURCE_RANGE[]; 54 | extern const char OSS_STS_SECURITY_TOKEN[]; 55 | extern const char OSS_REPLACE_OBJECT_META[]; 56 | extern const char OSS_LIFECYCLE[]; 57 | extern const char OSS_DELETE[]; 58 | extern const char OSS_YES[]; 59 | extern const int OSS_MAX_PART_NUM; 60 | extern const int OSS_PER_RET_NUM; 61 | extern const int MAX_SUFFIX_LEN; 62 | 63 | typedef struct oss_lib_curl_initializer_s oss_lib_curl_initializer_t; 64 | 65 | /** 66 | * oss_acl is an ACL that can be specified when an object is created or 67 | * updated. Each canned ACL has a predefined value when expanded to a full 68 | * set of OSS ACL Grants. 69 | * Private canned ACL gives the owner FULL_CONTROL and no other permissions 70 | * are issued 71 | * Public Read canned ACL gives the owner FULL_CONTROL and all users Read 72 | * permission 73 | * Public Read Write canned ACL gives the owner FULL_CONTROL and all users 74 | * Read and Write permission 75 | **/ 76 | typedef enum { 77 | OSS_ACL_PRIVATE = 0, /*< private */ 78 | OSS_ACL_PUBLIC_READ = 1, /*< public read */ 79 | OSS_ACL_PUBLIC_READ_WRITE = 2 /*< public read write */ 80 | } oss_acl_e; 81 | 82 | typedef struct { 83 | aos_string_t endpoint; 84 | aos_string_t access_key_id; 85 | aos_string_t access_key_secret; 86 | aos_string_t sts_token; 87 | int is_cname; 88 | } oss_config_t; 89 | 90 | typedef struct { 91 | oss_config_t *config; 92 | aos_http_controller_t *ctl; /*< aos http controller, more see aos_transport.h */ 93 | aos_pool_t *pool; 94 | } oss_request_options_t; 95 | 96 | typedef struct { 97 | aos_list_t node; 98 | aos_string_t key; 99 | aos_string_t last_modified; 100 | aos_string_t etag; 101 | aos_string_t size; 102 | aos_string_t owner_id; 103 | aos_string_t owner_display_name; 104 | } oss_list_object_content_t; 105 | 106 | typedef struct { 107 | aos_list_t node; 108 | aos_string_t prefix; 109 | } oss_list_object_common_prefix_t; 110 | 111 | typedef struct { 112 | aos_list_t node; 113 | aos_string_t key; 114 | aos_string_t upload_id; 115 | aos_string_t initiated; 116 | } oss_list_multipart_upload_content_t; 117 | 118 | typedef struct { 119 | aos_list_t node; 120 | aos_string_t part_number; 121 | aos_string_t size; 122 | aos_string_t etag; 123 | aos_string_t last_modified; 124 | } oss_list_part_content_t; 125 | 126 | typedef struct { 127 | aos_list_t node; 128 | aos_string_t part_number; 129 | aos_string_t etag; 130 | } oss_complete_part_content_t; 131 | 132 | typedef struct { 133 | int part_num; 134 | char *etag; 135 | } oss_upload_part_t; 136 | 137 | typedef struct { 138 | aos_string_t prefix; 139 | aos_string_t marker; 140 | aos_string_t delimiter; 141 | int max_ret; 142 | int truncated; 143 | aos_string_t next_marker; 144 | aos_list_t object_list; 145 | aos_list_t common_prefix_list; 146 | } oss_list_object_params_t; 147 | 148 | typedef struct { 149 | aos_string_t part_number_marker; 150 | int max_ret; 151 | int truncated; 152 | aos_string_t next_part_number_marker; 153 | aos_list_t part_list; 154 | } oss_list_upload_part_params_t; 155 | 156 | typedef struct { 157 | aos_string_t prefix; 158 | aos_string_t key_marker; 159 | aos_string_t upload_id_marker; 160 | aos_string_t delimiter; 161 | int max_ret; 162 | int truncated; 163 | aos_string_t next_key_marker; 164 | aos_string_t next_upload_id_marker; 165 | aos_list_t upload_list; 166 | } oss_list_multipart_upload_params_t; 167 | 168 | typedef struct { 169 | aos_string_t source_bucket; 170 | aos_string_t source_object; 171 | aos_string_t dest_bucket; 172 | aos_string_t dest_object; 173 | aos_string_t upload_id; 174 | int part_num; 175 | int64_t range_start; 176 | int64_t range_end; 177 | } oss_upload_part_copy_params_t; 178 | 179 | typedef struct { 180 | aos_string_t filename; /**< file range read filename */ 181 | int64_t file_pos; /**< file range read start position */ 182 | int64_t file_last; /**< file range read last position */ 183 | } oss_upload_file_t; 184 | 185 | typedef struct { 186 | aos_list_t node; 187 | aos_string_t id; 188 | aos_string_t prefix; 189 | aos_string_t status; 190 | int days; 191 | aos_string_t date; 192 | } oss_lifecycle_rule_content_t; 193 | 194 | typedef struct { 195 | aos_list_t node; 196 | aos_string_t key; 197 | } oss_object_key_t; 198 | 199 | typedef struct { 200 | char *suffix; 201 | char *type; 202 | } oss_content_type_t; 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /test/oss_test_util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "oss_config.h" 3 | #include "oss_api.h" 4 | #include "oss_test_util.h" 5 | 6 | void make_rand_string(aos_pool_t *p, int len, aos_string_t *data) 7 | { 8 | char *str = NULL; 9 | int i = 0; 10 | str = (char *)aos_palloc(p, len + 1); 11 | for ( ; i < len; i++) { 12 | str[i] = 'a' + rand() % 32; 13 | } 14 | str[len] = '\0'; 15 | aos_str_set(data, str); 16 | } 17 | 18 | aos_buf_t *make_random_buf(aos_pool_t *p, int len) 19 | { 20 | int bytes; 21 | aos_buf_t *b; 22 | aos_string_t str; 23 | 24 | make_rand_string(p, 16, &str); 25 | b = aos_create_buf(p, len); 26 | 27 | while (b->last < b->end) { 28 | bytes = b->end - b->last; 29 | bytes = aos_min(bytes, 16); 30 | memcpy(b->last, str.data, bytes); 31 | b->last += bytes; 32 | } 33 | 34 | return b; 35 | } 36 | 37 | void make_random_body(aos_pool_t *p, int count, aos_list_t *bc) 38 | { 39 | int i = 0; 40 | int len; 41 | aos_buf_t *b; 42 | 43 | for (; i < count; ++i) { 44 | len = random() % 4096; 45 | b = make_random_buf(p, len); 46 | aos_list_add_tail(&b->node, bc); 47 | } 48 | } 49 | 50 | void init_test_config(oss_config_t *config, int is_cname) 51 | { 52 | aos_str_set(&config->endpoint, TEST_OSS_ENDPOINT); 53 | aos_str_set(&config->access_key_id, TEST_ACCESS_KEY_ID); 54 | aos_str_set(&config->access_key_secret, TEST_ACCESS_KEY_SECRET); 55 | config->is_cname = is_cname; 56 | } 57 | 58 | void init_test_request_options(oss_request_options_t *options, int is_cname) 59 | { 60 | options->config = oss_config_create(options->pool); 61 | init_test_config(options->config, is_cname); 62 | options->ctl = aos_http_controller_create(options->pool, 0); 63 | } 64 | 65 | aos_status_t * create_test_bucket(const oss_request_options_t *options, 66 | const char *bucket_name, 67 | oss_acl_e oss_acl) 68 | { 69 | aos_string_t bucket; 70 | aos_table_t *resp_headers; 71 | aos_status_t * s; 72 | 73 | aos_str_set(&bucket, bucket_name); 74 | 75 | s = oss_create_bucket(options, &bucket, oss_acl, &resp_headers); 76 | return s; 77 | } 78 | 79 | aos_status_t *create_test_object(const oss_request_options_t *options, 80 | const char *bucket_name, 81 | const char *object_name, 82 | const char *data, 83 | aos_table_t *headers) 84 | { 85 | aos_string_t bucket; 86 | aos_string_t object; 87 | aos_table_t *resp_headers; 88 | aos_list_t buffer; 89 | aos_buf_t *content; 90 | aos_status_t * s; 91 | 92 | test_object_base(); 93 | aos_list_init(&buffer); 94 | content = aos_buf_pack(options->pool, data, strlen(data)); 95 | aos_list_add_tail(&content->node, &buffer); 96 | 97 | s = oss_put_object_from_buffer(options, &bucket, &object, 98 | &buffer, headers, &resp_headers); 99 | return s; 100 | } 101 | 102 | aos_status_t *create_test_object_from_file(const oss_request_options_t *options, 103 | const char *bucket_name, 104 | const char *object_name, 105 | const char *filename, 106 | aos_table_t *headers) 107 | { 108 | aos_string_t bucket; 109 | aos_string_t object; 110 | aos_string_t file; 111 | aos_table_t *resp_headers; 112 | aos_status_t * s; 113 | 114 | test_object_base(); 115 | aos_str_set(&file, filename); 116 | 117 | s = oss_put_object_from_file(options, &bucket, &object, &file, 118 | headers, &resp_headers); 119 | return s; 120 | } 121 | 122 | aos_status_t *delete_test_object(const oss_request_options_t *options, 123 | const char *bucket_name, 124 | const char *object_name) 125 | { 126 | aos_string_t bucket; 127 | aos_string_t object; 128 | aos_table_t *resp_headers; 129 | aos_status_t * s; 130 | 131 | test_object_base(); 132 | s = oss_delete_object(options, &bucket, &object, &resp_headers); 133 | return s; 134 | } 135 | 136 | aos_status_t *init_test_multipart_upload(const oss_request_options_t *options, 137 | const char *bucket_name, 138 | const char *object_name, 139 | aos_string_t *upload_id) 140 | { 141 | aos_string_t bucket; 142 | aos_string_t object; 143 | aos_table_t *headers; 144 | aos_table_t *resp_headers; 145 | aos_status_t *s; 146 | 147 | test_object_base(); 148 | headers = aos_table_make(options->pool, 5); 149 | 150 | s = oss_init_multipart_upload(options, &bucket, &object, 151 | upload_id, headers, &resp_headers); 152 | 153 | return s; 154 | } 155 | 156 | aos_status_t *abort_test_multipart_upload(const oss_request_options_t *options, 157 | const char *bucket_name, 158 | const char *object_name, 159 | aos_string_t *upload_id) 160 | { 161 | aos_string_t bucket; 162 | aos_string_t object; 163 | aos_table_t *resp_headers; 164 | aos_status_t *s; 165 | 166 | test_object_base(); 167 | s = oss_abort_multipart_upload(options, &bucket, &object, upload_id, 168 | &resp_headers); 169 | 170 | return s; 171 | } 172 | 173 | char* gen_test_signed_url(const oss_request_options_t *options, 174 | const char *bucket_name, 175 | const char *object_name, 176 | int64_t expires, 177 | aos_http_request_t *req) 178 | { 179 | aos_string_t bucket; 180 | aos_string_t object; 181 | char *signed_url = NULL; 182 | 183 | aos_str_set(&bucket, bucket_name); 184 | aos_str_set(&object, object_name); 185 | signed_url = oss_gen_signed_url(options, &bucket, &object, expires, req); 186 | return signed_url; 187 | } 188 | 189 | unsigned long get_file_size(const char *file_path) 190 | { 191 | unsigned long filesize = -1; 192 | struct stat statbuff; 193 | 194 | if(stat(file_path, &statbuff) < 0){ 195 | return filesize; 196 | } else { 197 | filesize = statbuff.st_size; 198 | } 199 | 200 | return filesize; 201 | } 202 | -------------------------------------------------------------------------------- /test/CuTest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003 Asim Jalis 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any 6 | * damages arising from the use of this software. 7 | * 8 | * Permission is granted to anyone to use this software for any 9 | * purpose, including commercial applications, and to alter it and 10 | * redistribute it freely, subject to the following restrictions: 11 | * 12 | * 1. The origin of this software must not be misrepresented; you 13 | * must not claim that you wrote the original software. If you use 14 | * this software in a product, an acknowledgment in the product 15 | * documentation would be appreciated but is not required. 16 | * 17 | * 2. Altered source versions must be plainly marked as such, and 18 | * must not be misrepresented as being the original software. 19 | * 20 | * 3. This notice may not be removed or altered from any source 21 | * distribution. 22 | *-------------------------------------------------------------------------* 23 | * 24 | * Originally obtained from "http://cutest.sourceforge.net/" version 1.4. 25 | * 26 | * Modified for serf as follows 27 | * 4) added CuSuiteSetSetupTeardownCallbacks to set a constructor and 28 | * destructor per test suite, run for each test. 29 | * 3) added CuAssertStrnEquals(), CuAssertStrnEquals_Msg() and 30 | * CuAssertStrnEquals_LineMsg() 31 | * 2) removed const from struct CuTest.name 32 | * 1) added CuStringFree(), CuTestFree(), CuSuiteFree(), and 33 | * CuSuiteFreeDeep() 34 | * 0) reformatted the whitespace (doh!) 35 | */ 36 | #ifndef CU_TEST_H 37 | #define CU_TEST_H 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | /* CuString */ 45 | 46 | char* CuStrAlloc(int size); 47 | char* CuStrCopy(const char* old); 48 | 49 | #define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) 50 | 51 | #define HUGE_STRING_LEN 8192 52 | #define STRING_MAX 256 53 | #define STRING_INC 256 54 | 55 | typedef struct 56 | { 57 | int length; 58 | int size; 59 | char* buffer; 60 | } CuString; 61 | 62 | void CuStringInit(CuString* str); 63 | CuString* CuStringNew(void); 64 | void CuStringFree(CuString *str); 65 | void CuStringRead(CuString* str, const char* path); 66 | void CuStringAppend(CuString* str, const char* text); 67 | void CuStringAppendChar(CuString* str, char ch); 68 | void CuStringAppendFormat(CuString* str, const char* format, ...); 69 | void CuStringInsert(CuString* str, const char* text, int pos); 70 | void CuStringResize(CuString* str, int newSize); 71 | 72 | /* CuTest */ 73 | 74 | typedef struct CuTest CuTest; 75 | 76 | typedef void (*TestFunction)(CuTest *); 77 | 78 | typedef void *(*TestCallback)(void *baton); 79 | 80 | struct CuTest 81 | { 82 | char* name; 83 | TestFunction function; 84 | int failed; 85 | int ran; 86 | const char* message; 87 | jmp_buf *jumpBuf; 88 | 89 | TestCallback setup; 90 | TestCallback teardown; 91 | void *testBaton; 92 | }; 93 | 94 | void CuTestInit(CuTest* t, const char* name, TestFunction function); 95 | CuTest* CuTestNew(const char* name, TestFunction function); 96 | void CuTestFree(CuTest* tc); 97 | void CuTestRun(CuTest* tc); 98 | 99 | /* Internal versions of assert functions -- use the public versions */ 100 | void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); 101 | void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); 102 | void CuAssertStrEquals_LineMsg(CuTest* tc, 103 | const char* file, int line, const char* message, 104 | const char* expected, const char* actual); 105 | void CuAssertStrnEquals_LineMsg(CuTest* tc, 106 | const char* file, int line, const char* message, 107 | const char* expected, size_t explen, const char* actual); 108 | void CuAssertIntEquals_LineMsg(CuTest* tc, 109 | const char* file, int line, const char* message, 110 | int expected, int actual); 111 | void CuAssertDblEquals_LineMsg(CuTest* tc, 112 | const char* file, int line, const char* message, 113 | double expected, double actual, double delta); 114 | void CuAssertPtrEquals_LineMsg(CuTest* tc, 115 | const char* file, int line, const char* message, 116 | void* expected, void* actual); 117 | 118 | /* public assert functions */ 119 | 120 | #define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms)) 121 | #define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond)) 122 | #define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond)) 123 | 124 | #define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) 125 | #define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) 126 | #define CuAssertStrnEquals(tc,ex,exlen,ac) CuAssertStrnEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(exlen),(ac)) 127 | #define CuAssertStrnEquals_Msg(tc,ms,ex,exlen,ac) CuAssertStrnEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(exlen),(ac)) 128 | #define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) 129 | #define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) 130 | #define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl)) 131 | #define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl)) 132 | #define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) 133 | #define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) 134 | 135 | #define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL)) 136 | #define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL)) 137 | 138 | /* CuSuite */ 139 | 140 | #define MAX_TEST_CASES 1024 141 | 142 | #define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST)) 143 | 144 | typedef struct 145 | { 146 | int count; 147 | CuTest* list[MAX_TEST_CASES]; 148 | int failCount; 149 | 150 | TestCallback setup; 151 | TestCallback teardown; 152 | void *testBaton; 153 | } CuSuite; 154 | 155 | 156 | void CuSuiteInit(CuSuite* testSuite); 157 | CuSuite* CuSuiteNew(void); 158 | void CuSuiteFree(CuSuite *testSuite); 159 | void CuSuiteFreeDeep(CuSuite *testSuite); 160 | void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase); 161 | void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2); 162 | void CuSuiteRun(CuSuite* testSuite); 163 | void CuSuiteSummary(CuSuite* testSuite, CuString* summary); 164 | void CuSuiteDetails(CuSuite* testSuite, CuString* details); 165 | 166 | void CuSuiteSetSetupTeardownCallbacks(CuSuite* testSuite, TestCallback setup, 167 | TestCallback teardown); 168 | 169 | #endif /* CU_TEST_H */ 170 | -------------------------------------------------------------------------------- /sample/oss_put_object_sample.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "aos_util.h" 3 | #include "aos_string.h" 4 | #include "aos_status.h" 5 | #include "oss_auth.h" 6 | #include "oss_util.h" 7 | #include "oss_api.h" 8 | #include "oss_config.h" 9 | #include "oss_sample_util.h" 10 | 11 | void put_object_from_buffer() 12 | { 13 | aos_pool_t *p = NULL; 14 | aos_string_t bucket; 15 | aos_string_t object; 16 | int is_cname = 0; 17 | aos_table_t *headers = NULL; 18 | aos_table_t *resp_headers = NULL; 19 | oss_request_options_t *options = NULL; 20 | aos_list_t buffer; 21 | aos_buf_t *content = NULL; 22 | char *str = "test oss c sdk"; 23 | aos_status_t *s = NULL; 24 | 25 | aos_pool_create(&p, NULL); 26 | options = oss_request_options_create(p); 27 | init_sample_request_options(options, is_cname); 28 | headers = aos_table_make(p, 1); 29 | apr_table_set(headers, "x-oss-meta-author", "oss"); 30 | aos_str_set(&bucket, BUCKET_NAME); 31 | aos_str_set(&object, OBJECT_NAME); 32 | 33 | aos_list_init(&buffer); 34 | content = aos_buf_pack(options->pool, str, strlen(str)); 35 | aos_list_add_tail(&content->node, &buffer); 36 | 37 | s = oss_put_object_from_buffer(options, &bucket, &object, 38 | &buffer, headers, &resp_headers); 39 | 40 | if (NULL != s && 2 == s->code / 100) { 41 | printf("put object from buffer succeeded\n"); 42 | } else { 43 | printf("put object from buffer failed\n"); 44 | } 45 | 46 | aos_pool_destroy(p); 47 | } 48 | 49 | void put_object_from_file() 50 | { 51 | aos_pool_t *p = NULL; 52 | aos_string_t bucket; 53 | aos_string_t object; 54 | int is_cname = 0; 55 | aos_table_t *headers = NULL; 56 | aos_table_t *resp_headers = NULL; 57 | oss_request_options_t *options = NULL; 58 | char *filename = __FILE__; 59 | aos_status_t *s = NULL; 60 | aos_string_t file; 61 | 62 | aos_pool_create(&p, NULL); 63 | options = oss_request_options_create(p); 64 | init_sample_request_options(options, is_cname); 65 | headers = aos_table_make(options->pool, 1); 66 | apr_table_set(headers, OSS_CONTENT_TYPE, "image/jpeg"); 67 | aos_str_set(&bucket, BUCKET_NAME); 68 | aos_str_set(&object, OBJECT_NAME); 69 | aos_str_set(&file, filename); 70 | 71 | s = oss_put_object_from_file(options, &bucket, &object, &file, 72 | headers, &resp_headers); 73 | 74 | if (NULL != s && 2 == s->code / 100) { 75 | printf("put object from file succeeded\n"); 76 | } else { 77 | printf("put object from file failed\n"); 78 | } 79 | 80 | aos_pool_destroy(p); 81 | } 82 | 83 | void put_object_by_signed_url() 84 | { 85 | aos_pool_t *p = NULL; 86 | aos_string_t bucket; 87 | aos_string_t object; 88 | aos_string_t url; 89 | int is_cname = 0; 90 | aos_http_request_t *request = NULL; 91 | aos_table_t *headers = NULL; 92 | aos_table_t *resp_headers = NULL; 93 | oss_request_options_t *options = NULL; 94 | char *filename = __FILE__; 95 | aos_status_t *s = NULL; 96 | aos_string_t file; 97 | char *signed_url = NULL; 98 | int64_t expires_time; 99 | 100 | aos_pool_create(&p, NULL); 101 | 102 | options = oss_request_options_create(p); 103 | init_sample_request_options(options, is_cname); 104 | 105 | // create request 106 | request = aos_http_request_create(p); 107 | request->method = HTTP_PUT; 108 | 109 | // create headers 110 | headers = aos_table_make(options->pool, 0); 111 | 112 | // set value 113 | aos_str_set(&bucket, BUCKET_NAME); 114 | aos_str_set(&object, OBJECT_NAME); 115 | aos_str_set(&file, filename); 116 | 117 | // expires time 118 | expires_time = apr_time_now() / 1000000 + 120; 119 | 120 | // generate signed url for put 121 | signed_url = oss_gen_signed_url(options, &bucket, &object, 122 | expires_time, request); 123 | aos_str_set(&url, signed_url); 124 | 125 | printf("signed put url : %s\n", signed_url); 126 | 127 | // put object by signed url 128 | s = oss_put_object_from_file_by_url(options, &url, &file, 129 | headers, &resp_headers); 130 | 131 | if (NULL != s && 2 == s->code / 100) { 132 | printf("put object by signed url succeeded\n"); 133 | } else { 134 | printf("put object by signed url failed\n"); 135 | } 136 | 137 | aos_pool_destroy(p); 138 | } 139 | 140 | void create_dir() 141 | { 142 | aos_pool_t *p = NULL; 143 | aos_string_t bucket; 144 | aos_string_t object; 145 | int is_cname = 0; 146 | aos_table_t *headers = NULL; 147 | aos_table_t *resp_headers = NULL; 148 | oss_request_options_t *options = NULL; 149 | aos_status_t *s = NULL; 150 | aos_list_t buffer; 151 | 152 | aos_pool_create(&p, NULL); 153 | options = oss_request_options_create(p); 154 | init_sample_request_options(options, is_cname); 155 | headers = aos_table_make(options->pool, 0); 156 | aos_str_set(&bucket, BUCKET_NAME); 157 | aos_str_set(&object, DIR_NAME); 158 | aos_list_init(&buffer); 159 | 160 | s = oss_put_object_from_buffer(options, &bucket, &object, &buffer, 161 | headers, &resp_headers); 162 | 163 | if (NULL != s && 2 == s->code / 100) { 164 | printf("create dir succeeded\n"); 165 | } else { 166 | printf("create dir failed\n"); 167 | } 168 | 169 | aos_pool_destroy(p); 170 | } 171 | 172 | void put_object_to_dir() 173 | { 174 | aos_pool_t *p = NULL; 175 | aos_string_t bucket; 176 | aos_string_t object; 177 | int is_cname = 0; 178 | aos_table_t *headers = NULL; 179 | aos_table_t *resp_headers = NULL; 180 | oss_request_options_t *options = NULL; 181 | char *filename = __FILE__; 182 | char *key = NULL; 183 | aos_status_t *s = NULL; 184 | aos_string_t file; 185 | 186 | aos_pool_create(&p, NULL); 187 | options = oss_request_options_create(p); 188 | init_sample_request_options(options, is_cname); 189 | headers = aos_table_make(options->pool, 0); 190 | aos_str_set(&bucket, BUCKET_NAME); 191 | 192 | key = (char*)malloc(strlen(DIR_NAME) + strlen(OBJECT_NAME) + 1); 193 | strcpy(key, DIR_NAME); 194 | strcat(key, OBJECT_NAME); 195 | aos_str_set(&object, key); 196 | aos_str_set(&file, filename); 197 | 198 | s = oss_put_object_from_file(options, &bucket, &object, &file, 199 | headers, &resp_headers); 200 | 201 | if (NULL != s && 2 == s->code / 100) { 202 | printf("put object to dir succeeded\n"); 203 | } else { 204 | printf("put object to dir failed\n"); 205 | } 206 | 207 | free(key); 208 | aos_pool_destroy(p); 209 | } 210 | 211 | int main(int argc, char *argv[]) 212 | { 213 | if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { 214 | exit(1); 215 | } 216 | 217 | put_object_from_buffer(); 218 | put_object_from_file(); 219 | put_object_by_signed_url(); 220 | 221 | create_dir(); 222 | put_object_to_dir(); 223 | 224 | aos_http_io_deinitialize(); 225 | 226 | return 0; 227 | } 228 | -------------------------------------------------------------------------------- /src/oss_util.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBOSS_UTIL_H 2 | #define LIBOSS_UTIL_H 3 | 4 | #include "aos_string.h" 5 | #include "aos_transport.h" 6 | #include "aos_status.h" 7 | #include "oss_define.h" 8 | 9 | OSS_CPP_START 10 | 11 | #define init_sts_token_header() do { \ 12 | if (options->config->sts_token.data != NULL) {\ 13 | apr_table_set(headers, OSS_STS_SECURITY_TOKEN, options->config->sts_token.data);\ 14 | }\ 15 | } while(0) 16 | 17 | /** 18 | * @brief check hostname ends with specific oss domain suffix. 19 | **/ 20 | int is_oss_domain(const aos_string_t *str); 21 | 22 | /** 23 | * @brief check hostname is ip. 24 | **/ 25 | int is_valid_ip(const char *str); 26 | 27 | /** 28 | * @brief get oss acl str according oss_acl 29 | * @param[in] oss_acl the oss bucket acl 30 | * @return oss acl str 31 | **/ 32 | const char *get_oss_acl_str(oss_acl_e oss_acl); 33 | 34 | /** 35 | * @brief create oss config including host, port, access_key_id, access_key_secret, is_oss_domain 36 | **/ 37 | oss_config_t *oss_config_create(aos_pool_t *p); 38 | 39 | /** 40 | * @brief create oss request options 41 | * @return oss request options 42 | **/ 43 | oss_request_options_t *oss_request_options_create(aos_pool_t *p); 44 | 45 | /** 46 | * @brief init oss request 47 | **/ 48 | void oss_init_request(const oss_request_options_t *options, http_method_e method, 49 | aos_http_request_t **req, aos_table_t *params, aos_table_t *headers, aos_http_response_t **resp); 50 | 51 | /** 52 | * @brief init oss bucket request 53 | **/ 54 | void oss_init_bucket_request(const oss_request_options_t *options, const aos_string_t *bucket, 55 | http_method_e method, aos_http_request_t **req, aos_table_t *params, aos_table_t *headers, 56 | aos_http_response_t **resp); 57 | 58 | /** 59 | * @brief init oss object request 60 | **/ 61 | void oss_init_object_request(const oss_request_options_t *options, const aos_string_t *bucket, 62 | const aos_string_t *object, http_method_e method, aos_http_request_t **req, 63 | aos_table_t *params, aos_table_t *headers, aos_http_response_t **resp); 64 | 65 | /** 66 | * @brief init oss request with signed_url 67 | **/ 68 | void oss_init_signed_url_request(const oss_request_options_t *options, const aos_string_t *signed_url, 69 | http_method_e method, aos_http_request_t **req, 70 | aos_table_t *params, aos_table_t *headers, aos_http_response_t **resp); 71 | 72 | /** 73 | * @brief oss send request 74 | **/ 75 | aos_status_t *oss_send_request(aos_http_controller_t *ctl, aos_http_request_t *req, 76 | aos_http_response_t *resp); 77 | 78 | /** 79 | * @brief process oss request including sign request, send request, get response 80 | **/ 81 | aos_status_t *oss_process_request(const oss_request_options_t *options, 82 | aos_http_request_t *req, aos_http_response_t *resp); 83 | 84 | /** 85 | * @brief process oss request with signed_url including send request, get response 86 | **/ 87 | aos_status_t *oss_process_signed_request(const oss_request_options_t *options, 88 | aos_http_request_t *req, aos_http_response_t *resp); 89 | 90 | /** 91 | * @brief get object uri using third-level domain if hostname is oss domain, otherwise second-level domain 92 | **/ 93 | void oss_get_object_uri(const oss_request_options_t *options, 94 | const aos_string_t *bucket, 95 | const aos_string_t *object, 96 | aos_http_request_t *req); 97 | 98 | /** 99 | * @brief bucket uri using third-level domain if hostname is oss domain, otherwise second-level domain 100 | **/ 101 | void oss_get_bucket_uri(const oss_request_options_t *options, 102 | const aos_string_t *bucket, 103 | aos_http_request_t *req); 104 | 105 | /** 106 | * @brief write body content into oss request body from buffer 107 | **/ 108 | void oss_write_request_body_from_buffer(aos_list_t *buffer, aos_http_request_t *req); 109 | 110 | /** 111 | * @brief write body content into oss request body from file 112 | **/ 113 | int oss_write_request_body_from_file(aos_pool_t *p, const aos_string_t *filename, aos_http_request_t *req); 114 | 115 | /** 116 | * @brief write body content into oss request body from multipart upload file 117 | **/ 118 | int oss_write_request_body_from_upload_file(aos_pool_t *p, oss_upload_file_t *upload_file, aos_http_request_t *req); 119 | 120 | /** 121 | * @brief read body content from oss response body to buffer 122 | **/ 123 | void oss_init_read_response_body_to_buffer(aos_list_t *buffer, aos_http_response_t *resp); 124 | 125 | /** 126 | * @brief read body content from oss response body to file 127 | **/ 128 | int oss_init_read_response_body_to_file(aos_pool_t *p, const aos_string_t *filename, aos_http_response_t *resp); 129 | 130 | /** 131 | * @brief create oss api result content 132 | * @return oss api result content 133 | **/ 134 | void *oss_create_api_result_content(aos_pool_t *p, size_t size); 135 | oss_list_object_content_t *oss_create_list_object_content(aos_pool_t *p); 136 | oss_list_object_common_prefix_t *oss_create_list_object_common_prefix(aos_pool_t *p); 137 | oss_list_part_content_t *oss_create_list_part_content(aos_pool_t *p); 138 | oss_list_multipart_upload_content_t *oss_create_list_multipart_upload_content(aos_pool_t *p); 139 | oss_complete_part_content_t *oss_create_complete_part_content(aos_pool_t *p); 140 | 141 | /** 142 | * @brief create oss api list parameters 143 | * @return oss api list parameters 144 | **/ 145 | oss_list_object_params_t *oss_create_list_object_params(aos_pool_t *p); 146 | oss_list_upload_part_params_t *oss_create_list_upload_part_params(aos_pool_t *p); 147 | oss_list_multipart_upload_params_t *oss_create_list_multipart_upload_params(aos_pool_t *p); 148 | 149 | /** 150 | * @brief create upload part copy params 151 | * @return upload part copy params struct for upload part copy 152 | **/ 153 | oss_upload_part_copy_params_t *oss_create_upload_part_copy_params(aos_pool_t *p); 154 | 155 | /** 156 | * @brief create upload file struct for range multipart upload 157 | * @return upload file struct for range multipart upload 158 | **/ 159 | oss_upload_file_t *oss_create_upload_file(aos_pool_t *p); 160 | 161 | /** 162 | * @brief get content-type for HTTP_POST request 163 | * @return content-type for HTTP_POST request 164 | **/ 165 | void oss_set_multipart_content_type(aos_table_t *headers); 166 | 167 | /** 168 | * @brief create lifecycle rule content 169 | * @return lifecycle rule content 170 | **/ 171 | oss_lifecycle_rule_content_t *oss_create_lifecycle_rule_content(aos_pool_t *p); 172 | 173 | /** 174 | * @brief create oss object content for delete objects 175 | * @return oss object content 176 | **/ 177 | oss_object_key_t *oss_create_oss_object_key(aos_pool_t *p); 178 | 179 | /** 180 | * @brief get part size for multipart upload 181 | **/ 182 | void oss_get_part_size(int64_t filesize, int64_t *part_size); 183 | 184 | /** 185 | * @brief compare function for part sort 186 | **/ 187 | int part_sort_cmp(const void *a, const void *b); 188 | 189 | /** 190 | * @brief set content type for object according to objectname 191 | * @return oss content type 192 | **/ 193 | char *get_content_type(const char *name); 194 | char *get_content_type_by_suffix(const char *suffix); 195 | 196 | /** 197 | * @brief set content type for object according to filename 198 | **/ 199 | void set_content_type(const char* filename, const char* key, aos_table_t *headers); 200 | 201 | aos_table_t* aos_table_create_if_null(const oss_request_options_t *options, 202 | aos_table_t *table, int table_size); 203 | 204 | OSS_CPP_END 205 | 206 | #endif 207 | -------------------------------------------------------------------------------- /sample/oss_get_object_sample.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "aos_util.h" 3 | #include "aos_string.h" 4 | #include "aos_status.h" 5 | #include "oss_auth.h" 6 | #include "oss_util.h" 7 | #include "oss_api.h" 8 | #include "oss_config.h" 9 | #include "oss_sample_util.h" 10 | 11 | void get_object_to_buffer() 12 | { 13 | aos_pool_t *p = NULL; 14 | aos_string_t bucket; 15 | aos_string_t object; 16 | int is_cname = 0; 17 | oss_request_options_t *options = NULL; 18 | aos_table_t *headers = NULL; 19 | aos_table_t *params = NULL; 20 | aos_table_t *resp_headers = NULL; 21 | aos_status_t *s = NULL; 22 | aos_list_t buffer; 23 | aos_buf_t *content = NULL; 24 | char *buf = NULL; 25 | int64_t len = 0; 26 | int64_t size = 0; 27 | int64_t pos = 0; 28 | 29 | aos_pool_create(&p, NULL); 30 | options = oss_request_options_create(p); 31 | init_sample_request_options(options, is_cname); 32 | aos_str_set(&bucket, BUCKET_NAME); 33 | aos_str_set(&object, OBJECT_NAME); 34 | aos_list_init(&buffer); 35 | 36 | s = oss_get_object_to_buffer(options, &bucket, &object, 37 | headers, params, &buffer, &resp_headers); 38 | 39 | if (NULL != s && 2 == s->code / 100) { 40 | printf("get object to buffer succeeded\n"); 41 | } 42 | else { 43 | printf("get object to buffer failed\n"); 44 | } 45 | 46 | //get buffer len 47 | aos_list_for_each_entry(content, &buffer, node) { 48 | len += aos_buf_size(content); 49 | } 50 | 51 | buf = aos_pcalloc(p, len + 1); 52 | buf[len] = '\0'; 53 | 54 | //copy buffer content to memory 55 | aos_list_for_each_entry(content, &buffer, node) { 56 | size = aos_buf_size(content); 57 | memcpy(buf + pos, content->pos, size); 58 | pos += size; 59 | } 60 | 61 | aos_pool_destroy(p); 62 | } 63 | 64 | void get_object_to_local_file() 65 | { 66 | aos_pool_t *p = NULL; 67 | aos_string_t bucket; 68 | char *download_filename = "get_object_to_local_file.txt"; 69 | aos_string_t object; 70 | int is_cname = 0; 71 | oss_request_options_t *options = NULL; 72 | aos_table_t *headers = NULL; 73 | aos_table_t *params = NULL; 74 | aos_table_t *resp_headers = NULL; 75 | aos_status_t *s = NULL; 76 | aos_string_t file; 77 | 78 | aos_pool_create(&p, NULL); 79 | options = oss_request_options_create(p); 80 | init_sample_request_options(options, is_cname); 81 | aos_str_set(&bucket, BUCKET_NAME); 82 | aos_str_set(&object, OBJECT_NAME); 83 | headers = aos_table_make(p, 0); 84 | aos_str_set(&file, download_filename); 85 | 86 | s = oss_get_object_to_file(options, &bucket, &object, headers, 87 | params, &file, &resp_headers); 88 | 89 | if (NULL != s && 2 == s->code / 100) { 90 | printf("get object to local file succeeded\n"); 91 | } else { 92 | printf("get object to local file failed\n"); 93 | } 94 | 95 | aos_pool_destroy(p); 96 | } 97 | 98 | void get_object_by_signed_url() 99 | { 100 | aos_pool_t *p = NULL; 101 | aos_string_t bucket; 102 | aos_string_t object; 103 | aos_string_t url; 104 | int is_cname = 0; 105 | aos_http_request_t *request = NULL; 106 | aos_table_t *headers = NULL; 107 | aos_table_t *params = NULL; 108 | aos_table_t *resp_headers = NULL; 109 | oss_request_options_t *options = NULL; 110 | aos_list_t buffer; 111 | aos_status_t *s = NULL; 112 | char *signed_url = NULL; 113 | int64_t expires_time; 114 | 115 | aos_pool_create(&p, NULL); 116 | 117 | options = oss_request_options_create(p); 118 | init_sample_request_options(options, is_cname); 119 | 120 | // create request 121 | request = aos_http_request_create(p); 122 | request->method = HTTP_GET; 123 | 124 | // create headers 125 | headers = aos_table_make(options->pool, 0); 126 | 127 | // set value 128 | aos_str_set(&bucket, BUCKET_NAME); 129 | aos_str_set(&object, OBJECT_NAME); 130 | aos_list_init(&buffer); 131 | 132 | // expires time 133 | expires_time = apr_time_now() / 1000000 + 120; 134 | 135 | // generate signed url for put 136 | signed_url = oss_gen_signed_url(options, &bucket, &object, 137 | expires_time, request); 138 | aos_str_set(&url, signed_url); 139 | 140 | printf("signed get url : %s\n", signed_url); 141 | 142 | // put object by signed url 143 | s = oss_get_object_to_buffer_by_url(options, &url, 144 | headers, params, &buffer, &resp_headers); 145 | 146 | if (NULL != s && 2 == s->code / 100) { 147 | printf("get object by signed url succeeded\n"); 148 | } else { 149 | printf("get object by signed url failed\n"); 150 | } 151 | 152 | aos_pool_destroy(p); 153 | } 154 | 155 | void get_oss_dir_to_local_dir() 156 | { 157 | aos_pool_t *parent_pool = NULL; 158 | aos_string_t bucket; 159 | int is_cname = 0; 160 | aos_status_t *s = NULL; 161 | oss_request_options_t *options = NULL; 162 | oss_list_object_params_t *params = NULL; 163 | 164 | aos_pool_create(&parent_pool, NULL); 165 | options = oss_request_options_create(parent_pool); 166 | init_sample_request_options(options, is_cname); 167 | aos_str_set(&bucket, BUCKET_NAME); 168 | params = oss_create_list_object_params(parent_pool); 169 | aos_str_set(¶ms->prefix, DIR_NAME); 170 | params->truncated = 1; 171 | 172 | while (params->truncated) { 173 | aos_pool_t *list_object_pool = NULL; 174 | aos_table_t *list_object_resp_headers = NULL; 175 | oss_list_object_content_t *list_content = NULL; 176 | 177 | aos_pool_create(&list_object_pool, parent_pool); 178 | options->pool = list_object_pool; 179 | s = oss_list_object(options, &bucket, params, &list_object_resp_headers); 180 | if (!aos_status_is_ok(s)) { 181 | aos_error_log("list objects of dir[%s] fail\n", DIR_NAME); 182 | aos_status_dup(parent_pool, s); 183 | aos_pool_destroy(list_object_pool); 184 | options->pool = parent_pool; 185 | return; 186 | } 187 | 188 | aos_list_for_each_entry(list_content, ¶ms->object_list, node) { 189 | if ('/' == list_content->key.data[strlen(list_content->key.data) - 1]) { 190 | apr_dir_make_recursive(list_content->key.data, 191 | APR_OS_DEFAULT, parent_pool); 192 | } else { 193 | aos_string_t object; 194 | aos_pool_t *get_object_pool = NULL; 195 | aos_table_t *headers = NULL; 196 | aos_table_t *query_params = NULL; 197 | aos_table_t *get_object_resp_headers = NULL; 198 | 199 | aos_str_set(&object, list_content->key.data); 200 | 201 | aos_pool_create(&get_object_pool, parent_pool); 202 | options->pool = get_object_pool; 203 | 204 | s = oss_get_object_to_file(options, &bucket, &object, 205 | headers, query_params, &object, &get_object_resp_headers); 206 | if (!aos_status_is_ok(s)) { 207 | aos_error_log("get object[%s] fail\n", object.data); 208 | } 209 | 210 | aos_pool_destroy(get_object_pool); 211 | options->pool = list_object_pool; 212 | } 213 | } 214 | 215 | aos_list_init(¶ms->object_list); 216 | if (params->next_marker.data) { 217 | aos_str_set(¶ms->marker, params->next_marker.data); 218 | } 219 | 220 | aos_pool_destroy(list_object_pool); 221 | } 222 | 223 | if (NULL != s && 2 == s->code / 100) { 224 | printf("get dir succeeded\n"); 225 | } else { 226 | printf("get dir failed\n"); 227 | } 228 | aos_pool_destroy(parent_pool); 229 | } 230 | 231 | int main(int argc, char *argv[]) 232 | { 233 | if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { 234 | exit(1); 235 | } 236 | 237 | get_object_to_buffer(); 238 | get_object_to_local_file(); 239 | get_object_by_signed_url(); 240 | 241 | get_oss_dir_to_local_dir(); 242 | 243 | aos_http_io_deinitialize(); 244 | 245 | return 0; 246 | } 247 | -------------------------------------------------------------------------------- /test/CuTest-README.txt: -------------------------------------------------------------------------------- 1 | Originally obtained from "http://cutest.sourceforge.net/" version 1.4. 2 | 3 | HOW TO USE 4 | 5 | You can use CuTest to create unit tests to drive your development 6 | in the style of Extreme Programming. You can also add unit tests to 7 | existing code to ensure that it works as you suspect. 8 | 9 | Your unit tests are an investment. They let you to change your 10 | code and add new features confidently without worrying about 11 | accidentally breaking earlier features. 12 | 13 | 14 | LICENSING 15 | 16 | Copyright (c) 2003 Asim Jalis 17 | 18 | This software is provided 'as-is', without any express or implied 19 | warranty. In no event will the authors be held liable for any damages 20 | arising from the use of this software. 21 | 22 | Permission is granted to anyone to use this software for any purpose, 23 | including commercial applications, and to alter it and redistribute it 24 | freely, subject to the following restrictions: 25 | 26 | 1. The origin of this software must not be misrepresented; you must not 27 | claim that you wrote the original software. If you use this software in 28 | a product, an acknowledgment in the product documentation would be 29 | appreciated but is not required. 30 | 31 | 2. Altered source versions must be plainly marked as such, and must not 32 | be misrepresented as being the original software. 33 | 34 | 3. This notice may not be removed or altered from any source 35 | distribution. 36 | 37 | 38 | GETTING STARTED 39 | 40 | To add unit testing to your C code the only files you need are 41 | CuTest.c and CuTest.h. 42 | 43 | CuTestTest.c and AllTests.c have been included to provide an 44 | example of how to write unit tests and then how to aggregate them 45 | into suites and into a single AllTests.c file. Suites allow you 46 | to put group tests into logical sets. AllTests.c combines all the 47 | suites and runs them. 48 | 49 | You should not have to look inside CuTest.c. Looking in 50 | CuTestTest.c and AllTests.c (for example usage) should be 51 | sufficient. 52 | 53 | After downloading the sources, run your compiler to create an 54 | executable called AllTests.exe. For example, if you are using 55 | Windows with the cl.exe compiler you would type: 56 | 57 | cl.exe AllTests.c CuTest.c CuTestTest.c 58 | AllTests.exe 59 | 60 | This will run all the unit tests associated with CuTest and print 61 | the output on the console. You can replace cl.exe with gcc or 62 | your favorite compiler in the command above. 63 | 64 | 65 | DETAILED EXAMPLE 66 | 67 | Here is a more detailed example. We will work through a simple 68 | test first exercise. The goal is to create a library of string 69 | utilities. First, lets write a function that converts a 70 | null-terminated string to all upper case. 71 | 72 | Ensure that CuTest.c and CuTest.h are accessible from your C 73 | project. Next, create a file called StrUtil.c with these 74 | contents: 75 | 76 | #include "CuTest.h" 77 | 78 | char* StrToUpper(char* str) { 79 | return str; 80 | } 81 | 82 | void TestStrToUpper(CuTest *tc) { 83 | char* input = strdup("hello world"); 84 | char* actual = StrToUpper(input); 85 | char* expected = "HELLO WORLD"; 86 | CuAssertStrEquals(tc, expected, actual); 87 | } 88 | 89 | CuSuite* StrUtilGetSuite() { 90 | CuSuite* suite = CuSuiteNew(); 91 | SUITE_ADD_TEST(suite, TestStrToUpper); 92 | return suite; 93 | } 94 | 95 | Create another file called AllTests.c with these contents: 96 | 97 | #include "CuTest.h" 98 | 99 | CuSuite* StrUtilGetSuite(); 100 | 101 | void RunAllTests(void) { 102 | CuString *output = CuStringNew(); 103 | CuSuite* suite = CuSuiteNew(); 104 | 105 | CuSuiteAddSuite(suite, StrUtilGetSuite()); 106 | 107 | CuSuiteRun(suite); 108 | CuSuiteSummary(suite, output); 109 | CuSuiteDetails(suite, output); 110 | printf("%s\n", output->buffer); 111 | } 112 | 113 | int main(void) { 114 | RunAllTests(); 115 | } 116 | 117 | Then type this on the command line: 118 | 119 | gcc AllTests.c CuTest.c StrUtil.c 120 | 121 | to compile. You can replace gcc with your favorite compiler. 122 | CuTest should be portable enough to handle all Windows and Unix 123 | compilers. Then to run the tests type: 124 | 125 | a.out 126 | 127 | This will print an error because we haven't implemented the 128 | StrToUpper function correctly. We are just returning the string 129 | without changing it to upper case. 130 | 131 | char* StrToUpper(char* str) { 132 | return str; 133 | } 134 | 135 | Rewrite this as follows: 136 | 137 | char* StrToUpper(char* str) { 138 | char* p; 139 | for (p = str ; *p ; ++p) *p = toupper(*p); 140 | return str; 141 | } 142 | 143 | Recompile and run the tests again. The test should pass this 144 | time. 145 | 146 | 147 | WHAT TO DO NEXT 148 | 149 | At this point you might want to write more tests for the 150 | StrToUpper function. Here are some ideas: 151 | 152 | TestStrToUpper_EmptyString : pass in "" 153 | TestStrToUpper_UpperCase : pass in "HELLO WORLD" 154 | TestStrToUpper_MixedCase : pass in "HELLO world" 155 | TestStrToUpper_Numbers : pass in "1234 hello" 156 | 157 | As you write each one of these tests add it to StrUtilGetSuite 158 | function. If you don't the tests won't be run. Later as you write 159 | other functions and write tests for them be sure to include those 160 | in StrUtilGetSuite also. The StrUtilGetSuite function should 161 | include all the tests in StrUtil.c 162 | 163 | Over time you will create another file called FunkyStuff.c 164 | containing other functions unrelated to StrUtil. Follow the same 165 | pattern. Create a FunkyStuffGetSuite function in FunkyStuff.c. 166 | And add FunkyStuffGetSuite to AllTests.c. 167 | 168 | The framework is designed in the way it is so that it is easy to 169 | organize a lot of tests. 170 | 171 | THE BIG PICTURE 172 | 173 | Each individual test corresponds to a CuTest. These are grouped 174 | to form a CuSuite. CuSuites can hold CuTests or other CuSuites. 175 | AllTests.c collects all the CuSuites in the program into a single 176 | CuSuite which it then runs as a single CuSuite. 177 | 178 | The project is open source so feel free to take a peek under the 179 | hood at the CuTest.c file to see how it works. CuTestTest.c 180 | contains tests for CuTest.c. So CuTest tests itself. 181 | 182 | Since AllTests.c has a main() you will need to exclude this when 183 | you are building your product. Here is a nicer way to do this if 184 | you want to avoid messing with multiple builds. Remove the main() 185 | in AllTests.c. Note that it just calls RunAllTests(). Instead 186 | we'll call this directly from the main program. 187 | 188 | Now in the main() of the actual program check to see if the 189 | command line option "--test" was passed. If it was then I call 190 | RunAllTests() from AllTests.c. Otherwise run the real program. 191 | 192 | Shipping the tests with the code can be useful. If you customers 193 | complain about a problem you can ask them to run the unit tests 194 | and send you the output. This can help you to quickly isolate the 195 | piece of your system that is malfunctioning in the customer's 196 | environment. 197 | 198 | CuTest offers a rich set of CuAssert functions. Here is a list: 199 | 200 | void CuAssert(CuTest* tc, char* message, int condition); 201 | void CuAssertTrue(CuTest* tc, int condition); 202 | void CuAssertStrEquals(CuTest* tc, char* expected, char* actual); 203 | void CuAssertIntEquals(CuTest* tc, int expected, int actual); 204 | void CuAssertPtrEquals(CuTest* tc, void* expected, void* actual); 205 | void CuAssertPtrNotNull(CuTest* tc, void* pointer); 206 | 207 | The project is open source and so you can add other more powerful 208 | asserts to make your tests easier to write and more concise. 209 | 210 | 211 | AUTOMATING TEST SUITE GENERATION 212 | 213 | make-tests.sh will grep through all the .c files in the current 214 | directory and generate the code to run all the tests contained in 215 | them. Using this script you don't have to worry about writing 216 | AllTests.c or dealing with any of the other suite code. 217 | 218 | 219 | CREDITS 220 | 221 | [02.23.2003] Dave Glowacki has added 222 | (1) file name and line numbers to the error messages, (2) 223 | AssertDblEquals for doubles, (3) AssertEquals_Msg version of 224 | all the AssertEquals to pass in optional message which is 225 | printed out on assert failure. 226 | -------------------------------------------------------------------------------- /sample/oss_multipart_upload_sample.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "aos_util.h" 3 | #include "aos_string.h" 4 | #include "aos_status.h" 5 | #include "oss_auth.h" 6 | #include "oss_util.h" 7 | #include "oss_api.h" 8 | #include "oss_config.h" 9 | #include "oss_sample_util.h" 10 | 11 | void multipart_upload_file_from_buffer() 12 | { 13 | aos_pool_t *p = NULL; 14 | aos_string_t bucket; 15 | aos_string_t object; 16 | int is_cname = 0; 17 | aos_table_t *headers = NULL; 18 | aos_table_t *resp_headers = NULL; 19 | oss_request_options_t *options = NULL; 20 | aos_string_t upload_id; 21 | aos_status_t *s = NULL; 22 | aos_list_t buffer; 23 | oss_list_upload_part_params_t *params = NULL; 24 | aos_list_t complete_part_list; 25 | oss_list_part_content_t *part_content = NULL; 26 | oss_complete_part_content_t *complete_part_content = NULL; 27 | int part_num1 = 1; 28 | int part_num2 = 2; 29 | 30 | aos_pool_create(&p, NULL); 31 | options = oss_request_options_create(p); 32 | init_sample_request_options(options, is_cname); 33 | headers = aos_table_make(p, 1); 34 | resp_headers = aos_table_make(options->pool, 5); 35 | aos_str_set(&bucket, BUCKET_NAME); 36 | aos_str_set(&object, OBJECT_NAME); 37 | 38 | //init mulitipart 39 | s = oss_init_multipart_upload(options, &bucket, &object, 40 | &upload_id, headers, &resp_headers); 41 | 42 | if (NULL != s && 2 == s->code / 100) { 43 | printf("Init multipart upload succeeded, upload_id:%.*s\n", 44 | upload_id.len, upload_id.data); 45 | } else { 46 | printf("Init multipart upload failed\n"); 47 | } 48 | 49 | //upload part 50 | aos_list_init(&buffer); 51 | make_random_body(p, 200, &buffer); 52 | s = oss_upload_part_from_buffer(options, &bucket, &object, &upload_id, 53 | part_num1, &buffer, &resp_headers); 54 | 55 | if (NULL != s && 2 == s->code / 100) { 56 | printf("Upload multipart part succeeded\n"); 57 | } else { 58 | printf("Upload multipart part failed\n"); 59 | } 60 | 61 | aos_list_init(&buffer); 62 | make_random_body(p, 10, &buffer); 63 | s = oss_upload_part_from_buffer(options, &bucket, &object, &upload_id, 64 | part_num2, &buffer, &resp_headers); 65 | 66 | if (NULL != s && 2 == s->code / 100) { 67 | printf("Upload multipart part succeeded\n"); 68 | } else { 69 | printf("Upload multipart part failed\n"); 70 | } 71 | 72 | //list part 73 | params = oss_create_list_upload_part_params(p); 74 | params->max_ret = 1000; 75 | aos_list_init(&complete_part_list); 76 | s = oss_list_upload_part(options, &bucket, &object, &upload_id, 77 | params, &resp_headers); 78 | 79 | if (NULL != s && 2 == s->code / 100) { 80 | printf("List multipart succeeded\n"); 81 | } else { 82 | printf("List multipart failed\n"); 83 | } 84 | 85 | aos_list_for_each_entry(part_content, ¶ms->part_list, node) { 86 | complete_part_content = oss_create_complete_part_content(p); 87 | aos_str_set(&complete_part_content->part_number, 88 | part_content->part_number.data); 89 | aos_str_set(&complete_part_content->etag, part_content->etag.data); 90 | aos_list_add_tail(&complete_part_content->node, &complete_part_list); 91 | } 92 | 93 | //complete multipart 94 | apr_table_add(headers, OSS_CONTENT_TYPE, "video/MP2T"); 95 | s = oss_complete_multipart_upload(options, &bucket, &object, &upload_id, 96 | &complete_part_list, headers, &resp_headers); 97 | 98 | if (NULL != s && 2 == s->code / 100) { 99 | printf("Complete multipart upload succeeded, upload_id:%.*s\n", 100 | upload_id.len, upload_id.data); 101 | } else { 102 | printf("Complete multipart upload failed\n"); 103 | } 104 | 105 | aos_pool_destroy(p); 106 | } 107 | 108 | void multipart_upload_file_from_file() 109 | { 110 | aos_pool_t *p = NULL; 111 | aos_string_t bucket; 112 | aos_string_t object; 113 | int is_cname = 0; 114 | aos_table_t *headers = NULL; 115 | aos_table_t *resp_headers = NULL; 116 | oss_request_options_t *options = NULL; 117 | aos_string_t upload_id; 118 | oss_upload_file_t *upload_file = NULL; 119 | aos_status_t *s = NULL; 120 | oss_list_upload_part_params_t *params = NULL; 121 | aos_list_t complete_part_list; 122 | oss_list_part_content_t *part_content = NULL; 123 | oss_complete_part_content_t *complete_part_content = NULL; 124 | int part_num1 = 1; 125 | int part_num2 = 2; 126 | 127 | aos_pool_create(&p, NULL); 128 | options = oss_request_options_create(p); 129 | init_sample_request_options(options, is_cname); 130 | headers = aos_table_make(p, 1); 131 | resp_headers = aos_table_make(options->pool, 5); 132 | aos_str_set(&bucket, BUCKET_NAME); 133 | aos_str_set(&object, OBJECT_NAME); 134 | 135 | //init mulitipart 136 | s = oss_init_multipart_upload(options, &bucket, &object, 137 | &upload_id, headers, &resp_headers); 138 | 139 | if (NULL != s && 2 == s->code / 100) { 140 | printf("Init multipart upload succeeded, upload_id:%.*s\n", 141 | upload_id.len, upload_id.data); 142 | } else { 143 | printf("Init multipart upload failed, upload_id:%.*s\n", 144 | upload_id.len, upload_id.data); 145 | } 146 | 147 | //upload part from file 148 | upload_file = oss_create_upload_file(p); 149 | aos_str_set(&upload_file->filename, MULTIPART_UPLOAD_FILE_PATH); 150 | upload_file->file_pos = 0; 151 | upload_file->file_last = 200 * 1024; //200k 152 | s = oss_upload_part_from_file(options, &bucket, &object, &upload_id, 153 | part_num1, upload_file, &resp_headers); 154 | 155 | if (NULL != s && 2 == s->code / 100) { 156 | printf("Multipart upload from file succeeded\n"); 157 | } else { 158 | printf("Multipart upload from file failed\n"); 159 | } 160 | 161 | upload_file->file_pos = 200 *1024;//remain content start pos 162 | upload_file->file_last = get_file_size(MULTIPART_UPLOAD_FILE_PATH); 163 | s = oss_upload_part_from_file(options, &bucket, &object, &upload_id, 164 | part_num2, upload_file, &resp_headers); 165 | 166 | if (NULL != s && 2 == s->code / 100) { 167 | printf("Multipart upload from file succeeded\n"); 168 | } else { 169 | printf("Multipart upload from file failed\n"); 170 | } 171 | 172 | //list part 173 | params = oss_create_list_upload_part_params(p); 174 | params->max_ret = 1000; 175 | aos_list_init(&complete_part_list); 176 | s = oss_list_upload_part(options, &bucket, &object, &upload_id, 177 | params, &resp_headers); 178 | 179 | if (NULL != s && 2 == s->code / 100) { 180 | printf("List multipart succeeded\n"); 181 | } else { 182 | printf("List multipart failed\n"); 183 | } 184 | 185 | aos_list_for_each_entry(part_content, ¶ms->part_list, node) { 186 | complete_part_content = oss_create_complete_part_content(p); 187 | aos_str_set(&complete_part_content->part_number, 188 | part_content->part_number.data); 189 | aos_str_set(&complete_part_content->etag, part_content->etag.data); 190 | aos_list_add_tail(&complete_part_content->node, &complete_part_list); 191 | } 192 | 193 | //complete multipart 194 | s = oss_complete_multipart_upload(options, &bucket, &object, &upload_id, 195 | &complete_part_list, headers, &resp_headers); 196 | 197 | if (NULL != s && 2 == s->code / 100) { 198 | printf("Complete multipart upload from file succeeded, upload_id:%.*s\n", 199 | upload_id.len, upload_id.data); 200 | } else { 201 | printf("Complete multipart upload from file failed\n"); 202 | } 203 | 204 | aos_pool_destroy(p); 205 | } 206 | 207 | void abort_multipart_upload() 208 | { 209 | aos_pool_t *p = NULL; 210 | aos_string_t bucket; 211 | aos_string_t object; 212 | int is_cname = 0; 213 | aos_table_t *headers = NULL; 214 | aos_table_t *resp_headers = NULL; 215 | oss_request_options_t *options = NULL; 216 | aos_string_t upload_id; 217 | aos_status_t *s = NULL; 218 | 219 | aos_pool_create(&p, NULL); 220 | options = oss_request_options_create(p); 221 | init_sample_request_options(options, is_cname); 222 | headers = aos_table_make(p, 1); 223 | aos_str_set(&bucket, BUCKET_NAME); 224 | aos_str_set(&object, OBJECT_NAME); 225 | 226 | s = oss_init_multipart_upload(options, &bucket, &object, 227 | &upload_id, headers, &resp_headers); 228 | 229 | if (NULL != s && 2 == s->code / 100) { 230 | printf("Init multipart upload succeeded, upload_id:%.*s\n", 231 | upload_id.len, upload_id.data); 232 | } else { 233 | printf("Init multipart upload failed\n"); 234 | } 235 | 236 | s = oss_abort_multipart_upload(options, &bucket, &object, &upload_id, 237 | &resp_headers); 238 | 239 | if (NULL != s && 2 == s->code / 100) { 240 | printf("Abort multipart upload succeeded, upload_id::%.*s\n", 241 | upload_id.len, upload_id.data); 242 | } else { 243 | printf("Abort multipart upload failed\n"); 244 | } 245 | 246 | aos_pool_destroy(p); 247 | } 248 | 249 | int main(int argc, char *argv[]) 250 | { 251 | if (aos_http_io_initialize(NULL, 0) != AOSE_OK) { 252 | exit(1); 253 | } 254 | 255 | multipart_upload_file_from_buffer(); 256 | multipart_upload_file_from_file(); 257 | abort_multipart_upload(); 258 | 259 | aos_http_io_deinitialize(); 260 | 261 | return 0; 262 | } 263 | -------------------------------------------------------------------------------- /src/aos_http_io.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "aos_http_io.h" 3 | #include "aos_define.h" 4 | #include 5 | #include 6 | 7 | aos_pool_t *aos_global_pool = NULL; 8 | apr_file_t *aos_stderr_file = NULL; 9 | 10 | aos_http_request_options_t *aos_default_http_request_options = NULL; 11 | aos_http_transport_options_t *aos_default_http_transport_options = NULL; 12 | 13 | aos_http_transport_create_pt aos_http_transport_create = aos_curl_http_transport_create; 14 | aos_http_transport_perform_pt aos_http_transport_perform = aos_curl_http_transport_perform; 15 | 16 | static pthread_mutex_t requestStackMutexG; 17 | static CURL *requestStackG[AOS_REQUEST_STACK_SIZE]; 18 | static int requestStackCountG; 19 | static char aos_user_agent[256]; 20 | 21 | 22 | static aos_http_transport_options_t *aos_http_transport_options_create(aos_pool_t *p); 23 | 24 | CURL *aos_request_get() 25 | { 26 | CURL *request = NULL; 27 | // Try to get one from the request stack. We hold the lock for the shortest time possible here. 28 | pthread_mutex_lock(&requestStackMutexG); 29 | if (requestStackCountG > 0) { 30 | request = requestStackG[--requestStackCountG]; 31 | } 32 | pthread_mutex_unlock(&requestStackMutexG); 33 | 34 | // If we got one, deinitialize it for re-use 35 | if (request) { 36 | curl_easy_reset(request); 37 | } 38 | else { 39 | request = curl_easy_init(); 40 | } 41 | 42 | return request; 43 | } 44 | 45 | void request_release(CURL *request) 46 | { 47 | pthread_mutex_lock(&requestStackMutexG); 48 | 49 | // If the request stack is full, destroy this one 50 | // else put this one at the front of the request stack; we do this because 51 | // we want the most-recently-used curl handle to be re-used on the next 52 | // request, to maximize our chances of re-using a TCP connection before it 53 | // times out 54 | if (requestStackCountG == AOS_REQUEST_STACK_SIZE) { 55 | pthread_mutex_unlock(&requestStackMutexG); 56 | curl_easy_cleanup(request); 57 | } 58 | else { 59 | requestStackG[requestStackCountG++] = request; 60 | pthread_mutex_unlock(&requestStackMutexG); 61 | } 62 | } 63 | 64 | void aos_set_default_request_options(aos_http_request_options_t *op) 65 | { 66 | aos_default_http_request_options = op; 67 | } 68 | 69 | void aos_set_default_transport_options(aos_http_transport_options_t *op) 70 | { 71 | aos_default_http_transport_options = op; 72 | } 73 | 74 | aos_http_request_options_t *aos_http_request_options_create(aos_pool_t *p) 75 | { 76 | aos_http_request_options_t *options; 77 | 78 | options = (aos_http_request_options_t *)aos_pcalloc(p, sizeof(aos_http_request_options_t)); 79 | options->speed_limit = AOS_MIN_SPEED_LIMIT; 80 | options->speed_time = AOS_MIN_SPEED_TIME; 81 | options->connect_timeout = AOS_CONNECT_TIMEOUT; 82 | options->dns_cache_timeout = AOS_DNS_CACHE_TIMOUT; 83 | options->max_memory_size = AOS_MAX_MEMORY_SIZE; 84 | 85 | return options; 86 | } 87 | 88 | aos_http_transport_options_t *aos_http_transport_options_create(aos_pool_t *p) 89 | { 90 | return (aos_http_transport_options_t *)aos_pcalloc(p, sizeof(aos_http_transport_options_t)); 91 | } 92 | 93 | aos_http_controller_t *aos_http_controller_create(aos_pool_t *p, int owner) 94 | { 95 | int s; 96 | aos_http_controller_t *ctl; 97 | 98 | if(p == NULL) { 99 | if ((s = aos_pool_create(&p, NULL)) != APR_SUCCESS) { 100 | aos_fatal_log("aos_pool_create failure."); 101 | return NULL; 102 | } 103 | } 104 | ctl = (aos_http_controller_t *)aos_pcalloc(p, sizeof(aos_http_controller_ex_t)); 105 | ctl->pool = p; 106 | ctl->owner = owner; 107 | ctl->options = aos_default_http_request_options; 108 | 109 | return ctl; 110 | } 111 | 112 | aos_http_request_t *aos_http_request_create(aos_pool_t *p) 113 | { 114 | aos_http_request_t *req; 115 | 116 | req = (aos_http_request_t *)aos_pcalloc(p, sizeof(aos_http_request_t)); 117 | req->method = HTTP_GET; 118 | req->headers = aos_table_make(p, 5); 119 | req->query_params = aos_table_make(p, 3); 120 | aos_list_init(&req->body); 121 | req->type = BODY_IN_MEMORY; 122 | req->body_len = 0; 123 | req->pool = p; 124 | req->read_body = aos_read_http_body_memory; 125 | 126 | return req; 127 | } 128 | 129 | aos_http_response_t *aos_http_response_create(aos_pool_t *p) 130 | { 131 | aos_http_response_t *resp; 132 | 133 | resp = (aos_http_response_t *)aos_pcalloc(p, sizeof(aos_http_response_t)); 134 | resp->status = -1; 135 | resp->headers = aos_table_make(p, 10); 136 | aos_list_init(&resp->body); 137 | resp->type = BODY_IN_MEMORY; 138 | resp->body_len = 0; 139 | resp->pool = p; 140 | resp->write_body = aos_write_http_body_memory; 141 | 142 | return resp; 143 | } 144 | 145 | int aos_read_http_body_memory(aos_http_request_t *req, char *buffer, int len) 146 | { 147 | int wsize; 148 | int bytes = 0; 149 | aos_buf_t *b; 150 | aos_buf_t *n; 151 | 152 | aos_list_for_each_entry_safe(b, n, &req->body, node) { 153 | wsize = aos_buf_size(b); 154 | if (wsize == 0) { 155 | aos_list_del(&b->node); 156 | continue; 157 | } 158 | wsize = aos_min(len - bytes, wsize); 159 | if (wsize == 0) { 160 | break; 161 | } 162 | memcpy(buffer + bytes, b->pos, wsize); 163 | b->pos += wsize; 164 | bytes += wsize; 165 | if (b->pos == b->last) { 166 | aos_list_del(&b->node); 167 | } 168 | } 169 | 170 | return bytes; 171 | } 172 | 173 | int aos_read_http_body_file(aos_http_request_t *req, char *buffer, int len) 174 | { 175 | int s; 176 | char buf[256]; 177 | apr_size_t nbytes = len; 178 | apr_size_t bytes_left; 179 | 180 | if (req->file_buf == NULL || req->file_buf->file == NULL) { 181 | aos_error_log("request body arg invalid file_buf NULL."); 182 | return AOSE_INVALID_ARGUMENT; 183 | } 184 | 185 | if (req->file_buf->file_pos >= req->file_buf->file_last) { 186 | aos_debug_log("file read finish."); 187 | return 0; 188 | } 189 | 190 | bytes_left = req->file_buf->file_last - req->file_buf->file_pos; 191 | if (nbytes > bytes_left) { 192 | nbytes = bytes_left; 193 | } 194 | 195 | if ((s = apr_file_read(req->file_buf->file, buffer, &nbytes)) != APR_SUCCESS) { 196 | aos_error_log("apr_file_read filure, code:%d %s.", s, apr_strerror(s, buf, sizeof(buf))); 197 | return AOSE_FILE_READ_ERROR; 198 | } 199 | req->file_buf->file_pos += nbytes; 200 | return nbytes; 201 | } 202 | 203 | int aos_write_http_body_memory(aos_http_response_t *resp, const char *buffer, int len) 204 | { 205 | aos_buf_t *b; 206 | 207 | b = aos_create_buf(resp->pool, len); 208 | memcpy(b->pos, buffer, len); 209 | b->last += len; 210 | aos_list_add_tail(&b->node, &resp->body); 211 | resp->body_len += len; 212 | 213 | return len; 214 | } 215 | 216 | int aos_write_http_body_file(aos_http_response_t *resp, const char *buffer, int len) 217 | { 218 | int elen; 219 | int s; 220 | char buf[256]; 221 | apr_size_t nbytes = len; 222 | 223 | if (resp->file_buf == NULL) { 224 | resp->file_buf = aos_create_file_buf(resp->pool); 225 | } 226 | 227 | if (resp->file_buf->file == NULL) { 228 | if (resp->file_path == NULL) { 229 | aos_error_log("resp body file arg NULL."); 230 | return AOSE_INVALID_ARGUMENT; 231 | } 232 | aos_trace_log("open file %s.", resp->file_path); 233 | if ((elen = aos_open_file_for_write(resp->pool, resp->file_path, resp->file_buf)) != AOSE_OK) { 234 | return elen; 235 | } 236 | } 237 | 238 | assert(resp->file_buf->file != NULL); 239 | if ((s = apr_file_write(resp->file_buf->file, buffer, &nbytes)) != APR_SUCCESS) { 240 | aos_error_log("apr_file_write fialure, code:%d %s.", s, apr_strerror(s, buf, sizeof(buf))); 241 | return AOSE_FILE_WRITE_ERROR; 242 | } 243 | 244 | resp->file_buf->file_last += nbytes; 245 | resp->body_len += nbytes; 246 | 247 | return nbytes; 248 | } 249 | 250 | int aos_http_io_initialize(const char *user_agent_info, int flags) 251 | { 252 | CURLcode ecode; 253 | int s; 254 | char buf[256]; 255 | aos_http_request_options_t *req_options; 256 | aos_http_transport_options_t *trans_options; 257 | 258 | pthread_mutex_init(&requestStackMutexG, 0); 259 | requestStackCountG = 0; 260 | 261 | if ((ecode = curl_global_init(CURL_GLOBAL_ALL & 262 | ~((flags & AOS_INIT_WINSOCK) ? 0: CURL_GLOBAL_WIN32))) != CURLE_OK) 263 | { 264 | aos_error_log("curl_global_init failure, code:%d %s.\n", ecode, curl_easy_strerror(ecode)); 265 | return AOSE_INTERNAL_ERROR; 266 | } 267 | 268 | if ((s = apr_initialize()) != APR_SUCCESS) { 269 | aos_error_log("apr_initialize failue.\n"); 270 | return AOSE_INTERNAL_ERROR; 271 | } 272 | 273 | if (!user_agent_info || !*user_agent_info) { 274 | user_agent_info = "Unknown"; 275 | } 276 | 277 | if ((s = aos_pool_create(&aos_global_pool, NULL)) != APR_SUCCESS) { 278 | aos_error_log("aos_pool_create failure, code:%d %s.\n", s, apr_strerror(s, buf, sizeof(buf))); 279 | return AOSE_INTERNAL_ERROR; 280 | } 281 | apr_snprintf(aos_user_agent, sizeof(aos_user_agent)-1, "%s(Compatible %s)", 282 | AOS_VER, user_agent_info); 283 | 284 | if ((s = apr_file_open_stderr(&aos_stderr_file, aos_global_pool)) != APR_SUCCESS) { 285 | aos_error_log("apr_file_open_stderr failure, code:%d %s.\n", s, apr_strerror(s, buf, sizeof(buf))); 286 | return AOSE_INTERNAL_ERROR; 287 | } 288 | 289 | req_options = aos_http_request_options_create(aos_global_pool); 290 | trans_options = aos_http_transport_options_create(aos_global_pool); 291 | trans_options->user_agent = aos_user_agent; 292 | 293 | aos_set_default_request_options(req_options); 294 | aos_set_default_transport_options(trans_options); 295 | 296 | return AOSE_OK; 297 | } 298 | 299 | void aos_http_io_deinitialize() 300 | { 301 | pthread_mutex_destroy(&requestStackMutexG); 302 | while (requestStackCountG--) { 303 | curl_easy_cleanup(requestStackG[requestStackCountG]); 304 | } 305 | 306 | if (aos_stderr_file != NULL) { 307 | apr_file_close(aos_stderr_file); 308 | aos_stderr_file = NULL; 309 | } 310 | if (aos_global_pool != NULL) { 311 | aos_pool_destroy(aos_global_pool); 312 | aos_global_pool = NULL; 313 | } 314 | apr_terminate(); 315 | } 316 | 317 | int aos_http_send_request(aos_http_controller_t *ctl, aos_http_request_t *req, aos_http_response_t *resp) 318 | { 319 | aos_http_transport_t *t; 320 | 321 | t = aos_http_transport_create(ctl->pool); 322 | t->req = req; 323 | t->resp = resp; 324 | t->controller = (aos_http_controller_ex_t *)ctl; 325 | 326 | return aos_http_transport_perform(t); 327 | } 328 | 329 | -------------------------------------------------------------------------------- /src/aos_util.c: -------------------------------------------------------------------------------- 1 | #include "aos_util.h" 2 | #include "aos_log.h" 3 | 4 | static const char *g_s_wday[] = { 5 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 6 | }; 7 | 8 | static const char *g_s_mon[] = { 9 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 10 | }; 11 | 12 | static const char g_s_gmt_format[] = "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT"; 13 | 14 | int aos_parse_xml_body(aos_list_t *bc, mxml_node_t **root) 15 | { 16 | aos_buf_t *b; 17 | size_t len; 18 | 19 | *root = NULL; 20 | len = (size_t)aos_buf_list_len(bc); 21 | 22 | { 23 | int nsize = 0; 24 | char *buffer = (char*)malloc(sizeof(char)*(len+1)); 25 | memset(buffer, 0, len + 1); 26 | aos_list_for_each_entry(b, bc, node) { 27 | memcpy(buffer + nsize, (char *)b->pos, aos_buf_size(b)); 28 | nsize += aos_buf_size(b); 29 | } 30 | *root = mxmlLoadString(NULL, buffer, MXML_OPAQUE_CALLBACK); 31 | free(buffer); 32 | if (NULL == *root) { 33 | return AOSE_INTERNAL_ERROR; 34 | } 35 | } 36 | 37 | return AOSE_OK; 38 | } 39 | 40 | int aos_convert_to_gmt_time(char* date, const char* format, apr_time_exp_t *tm) 41 | { 42 | int size = apr_snprintf(date, AOS_MAX_GMT_TIME_LEN, format, 43 | g_s_wday[tm->tm_wday], tm->tm_mday, g_s_mon[tm->tm_mon], 1900 + tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec); 44 | if (size >= 0 && size < AOS_MAX_GMT_TIME_LEN) { 45 | return AOSE_OK; 46 | } else { 47 | return AOSE_INTERNAL_ERROR; 48 | } 49 | } 50 | 51 | int aos_get_gmt_str_time(char datestr[AOS_MAX_GMT_TIME_LEN]) 52 | { 53 | int s; 54 | apr_time_t now; 55 | char buf[128]; 56 | apr_time_exp_t result; 57 | 58 | now = apr_time_now(); 59 | if ((s = apr_time_exp_gmt(&result, now)) != APR_SUCCESS) { 60 | aos_error_log("apr_time_exp_gmt fialure, code:%d %s.", s, apr_strerror(s, buf, sizeof(buf))); 61 | return AOSE_INTERNAL_ERROR; 62 | } 63 | 64 | if ((s = aos_convert_to_gmt_time(datestr, g_s_gmt_format, &result)) 65 | != AOSE_OK) { 66 | aos_error_log("aos_convert_to_GMT failure, code:%d.", s); 67 | } 68 | 69 | return s; 70 | } 71 | 72 | int aos_url_encode(char *dest, const char *src, int maxSrcSize) 73 | { 74 | static const char *hex = "0123456789ABCDEF"; 75 | 76 | int len = 0; 77 | unsigned char c; 78 | 79 | while (*src) { 80 | if (++len > maxSrcSize) { 81 | *dest = 0; 82 | return AOSE_INVALID_ARGUMENT; 83 | } 84 | c = *src; 85 | if (isalnum(c) || 86 | (c == '-') || (c == '_') || (c == '.') || (c == '!') || 87 | (c == '~') || (c == '*') || (c == '\'') || (c == '(') || 88 | (c == ')') || (c == '/')) { 89 | *dest++ = c; 90 | } else if (*src == ' ') { 91 | // *dest++ = '+'; 92 | *dest++ = '%'; 93 | *dest++ = '2'; 94 | *dest++ = '0'; 95 | } else { 96 | *dest++ = '%'; 97 | *dest++ = hex[c >> 4]; 98 | *dest++ = hex[c & 15]; 99 | } 100 | src++; 101 | } 102 | 103 | *dest = 0; 104 | 105 | return AOSE_OK; 106 | } 107 | 108 | int aos_query_params_to_string(aos_pool_t *p, aos_table_t *query_params, aos_string_t *querystr) 109 | { 110 | int rs; 111 | int pos; 112 | int len; 113 | char sep = '?'; 114 | char ebuf[AOS_MAX_QUERY_ARG_LEN*3+1]; 115 | char abuf[AOS_MAX_QUERY_ARG_LEN*6+128]; 116 | int max_len; 117 | const aos_array_header_t *tarr; 118 | const aos_table_entry_t *telts; 119 | aos_buf_t *querybuf; 120 | 121 | if (apr_is_empty_table(query_params)) { 122 | return AOSE_OK; 123 | } 124 | 125 | max_len = sizeof(abuf)-1; 126 | querybuf = aos_create_buf(p, 256); 127 | aos_str_null(querystr); 128 | 129 | tarr = aos_table_elts(query_params); 130 | telts = (aos_table_entry_t*)tarr->elts; 131 | 132 | for (pos = 0; pos < tarr->nelts; ++pos) { 133 | if ((rs = aos_url_encode(ebuf, telts[pos].key, AOS_MAX_QUERY_ARG_LEN)) != AOSE_OK) { 134 | aos_error_log("query params args too big, key:%s.", telts[pos].key); 135 | return AOSE_INVALID_ARGUMENT; 136 | } 137 | len = apr_snprintf(abuf, max_len, "%c%s", sep, ebuf); 138 | if (telts[pos].val != NULL && *telts[pos].val != '\0') { 139 | if ((rs = aos_url_encode(ebuf, telts[pos].val, AOS_MAX_QUERY_ARG_LEN)) != AOSE_OK) { 140 | aos_error_log("query params args too big, value:%s.", telts[pos].val); 141 | return AOSE_INVALID_ARGUMENT; 142 | } 143 | len += apr_snprintf(abuf+len, max_len-len, "=%s", ebuf); 144 | if (len >= AOS_MAX_QUERY_ARG_LEN) { 145 | aos_error_log("query params args too big, %s.", abuf); 146 | return AOSE_INVALID_ARGUMENT; 147 | } 148 | } 149 | aos_buf_append_string(p, querybuf, abuf, len); 150 | sep = '&'; 151 | } 152 | 153 | // result 154 | querystr->data = (char *)querybuf->pos; 155 | querystr->len = aos_buf_size(querybuf); 156 | 157 | return AOSE_OK; 158 | } 159 | 160 | void aos_gnome_sort(const char **headers, int size) 161 | { 162 | const char *tmp; 163 | int i = 0, last_highest = 0; 164 | 165 | while (i < size) { 166 | if ((i == 0) || apr_strnatcasecmp(headers[i-1], headers[i]) < 0) { 167 | i = ++last_highest; 168 | } else { 169 | tmp = headers[i]; 170 | headers[i] = headers[i - 1]; 171 | headers[--i] = tmp; 172 | } 173 | } 174 | } 175 | 176 | const char* aos_http_method_to_string(http_method_e method) 177 | { 178 | switch (method) { 179 | case HTTP_GET: 180 | return "GET"; 181 | case HTTP_HEAD: 182 | return "HEAD"; 183 | case HTTP_PUT: 184 | return "PUT"; 185 | case HTTP_POST: 186 | return "POST"; 187 | case HTTP_DELETE: 188 | return "DELETE"; 189 | default: 190 | return "UNKNOWN"; 191 | } 192 | } 193 | 194 | int aos_base64_encode(const unsigned char *in, int inLen, char *out) 195 | { 196 | static const char *ENC = 197 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 198 | 199 | char *original_out = out; 200 | 201 | while (inLen) { 202 | // first 6 bits of char 1 203 | *out++ = ENC[*in >> 2]; 204 | if (!--inLen) { 205 | // last 2 bits of char 1, 4 bits of 0 206 | *out++ = ENC[(*in & 0x3) << 4]; 207 | *out++ = '='; 208 | *out++ = '='; 209 | break; 210 | } 211 | // last 2 bits of char 1, first 4 bits of char 2 212 | *out++ = ENC[((*in & 0x3) << 4) | (*(in + 1) >> 4)]; 213 | in++; 214 | if (!--inLen) { 215 | // last 4 bits of char 2, 2 bits of 0 216 | *out++ = ENC[(*in & 0xF) << 2]; 217 | *out++ = '='; 218 | break; 219 | } 220 | // last 4 bits of char 2, first 2 bits of char 3 221 | *out++ = ENC[((*in & 0xF) << 2) | (*(in + 1) >> 6)]; 222 | in++; 223 | // last 6 bits of char 3 224 | *out++ = ENC[*in & 0x3F]; 225 | in++, inLen--; 226 | } 227 | 228 | return (out - original_out); 229 | } 230 | 231 | // HMAC-SHA-1: 232 | // 233 | // K - is key padded with zeros to 512 bits 234 | // m - is message 235 | // OPAD - 0x5c5c5c... 236 | // IPAD - 0x363636... 237 | // 238 | // HMAC(K,m) = SHA1((K ^ OPAD) . SHA1((K ^ IPAD) . m)) 239 | void HMAC_SHA1(unsigned char hmac[20], const unsigned char *key, int key_len, 240 | const unsigned char *message, int message_len) 241 | { 242 | unsigned char kopad[64], kipad[64]; 243 | int i; 244 | unsigned char digest[APR_SHA1_DIGESTSIZE]; 245 | apr_sha1_ctx_t context; 246 | 247 | if (key_len > 64) { 248 | key_len = 64; 249 | } 250 | 251 | for (i = 0; i < key_len; i++) { 252 | kopad[i] = key[i] ^ 0x5c; 253 | kipad[i] = key[i] ^ 0x36; 254 | } 255 | 256 | for ( ; i < 64; i++) { 257 | kopad[i] = 0 ^ 0x5c; 258 | kipad[i] = 0 ^ 0x36; 259 | } 260 | 261 | apr_sha1_init(&context); 262 | apr_sha1_update(&context, (const char *)kipad, 64); 263 | apr_sha1_update(&context, (const char *)message, (unsigned int)message_len); 264 | apr_sha1_final(digest, &context); 265 | 266 | apr_sha1_init(&context); 267 | apr_sha1_update(&context, (const char *)kopad, 64); 268 | apr_sha1_update(&context, (const char *)digest, 20); 269 | apr_sha1_final(hmac, &context); 270 | } 271 | 272 | unsigned char* aos_md5(aos_pool_t* pool, const char *in, apr_size_t in_len) { 273 | unsigned char* out; 274 | apr_md5_ctx_t context; 275 | 276 | //APR_MD5_DIGESTSIZE: The MD5 digest size, value is 16 277 | out = aos_palloc(pool, APR_MD5_DIGESTSIZE + 1); 278 | if (!out) { 279 | return NULL; 280 | } 281 | 282 | if (0 != apr_md5_init(&context)) { 283 | return NULL; 284 | } 285 | 286 | if (0 != apr_md5_update(&context, in, in_len)) { 287 | return NULL; 288 | } 289 | 290 | if (0 != apr_md5_final(out, &context)) { 291 | return NULL; 292 | } 293 | out[APR_MD5_DIGESTSIZE] = '\0'; 294 | return out; 295 | }; 296 | 297 | int aos_url_decode(const char *in, char *out) 298 | { 299 | static const char tbl[256] = { 300 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 301 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 302 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 303 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, 304 | -1,10,11,12,13,14,15,-1, -1,-1,-1,-1,-1,-1,-1,-1, 305 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 306 | -1,10,11,12,13,14,15,-1, -1,-1,-1,-1,-1,-1,-1,-1, 307 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 308 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 309 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 310 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 311 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 312 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 313 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 314 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, 315 | -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1 316 | }; 317 | char c, v1, v2; 318 | 319 | if(in != NULL) { 320 | while((c=*in++) != '\0') { 321 | if(c == '%') { 322 | if(!(v1=*in++) || (v1=tbl[(unsigned char)v1])<0 || 323 | !(v2=*in++) || (v2=tbl[(unsigned char)v2])<0) { 324 | *out = '\0'; 325 | return -1; 326 | } 327 | c = (v1<<4)|v2; 328 | } else if (c == '+') { 329 | c = ' '; 330 | } 331 | *out++ = c; 332 | } 333 | } 334 | *out = '\0'; 335 | return 0; 336 | } 337 | -------------------------------------------------------------------------------- /test/test_aos.c: -------------------------------------------------------------------------------- 1 | #include "CuTest.h" 2 | #include "test.h" 3 | #include "apr_portable.h" 4 | #include "apr_file_info.h" 5 | #include "aos_log.h" 6 | #include "aos_util.h" 7 | #include "aos_string.h" 8 | #include "aos_status.h" 9 | #include "oss_auth.h" 10 | #include "oss_util.c" 11 | #include "aos_transport.c" 12 | 13 | /* 14 | * oss_xml.c 15 | */ 16 | void test_get_xml_doc_with_empty_aos_list(CuTest *tc) 17 | { 18 | int ret; 19 | mxml_node_t *xml_node; 20 | aos_list_t bc; 21 | aos_list_init(&bc); 22 | 23 | 24 | ret = get_xmldoc(&bc, &xml_node); 25 | CuAssertIntEquals(tc, AOSE_XML_PARSE_ERROR, ret); 26 | 27 | printf("test_get_xml_doc_with_empty_aos_list ok\n"); 28 | } 29 | 30 | /* 31 | * aos_list.h 32 | */ 33 | 34 | void test_aos_list_movelist_with_empty_list(CuTest *tc) { 35 | aos_list_t list; 36 | aos_list_t new_list; 37 | 38 | aos_list_init(&list); 39 | 40 | aos_list_movelist(&list, &new_list); 41 | CuAssertTrue(tc, new_list.prev == &new_list); 42 | CuAssertTrue(tc, new_list.next == &new_list); 43 | 44 | printf("test_aos_list_movelist_with_empty_list ok\n"); 45 | } 46 | 47 | /* 48 | * oss_util.c 49 | */ 50 | void test_starts_with_failed(CuTest *tc) { 51 | int ret; 52 | aos_string_t str; 53 | aos_str_set(&str, "hangzhou.city"); 54 | 55 | ret = starts_with(&str, "xixi"); 56 | CuAssertIntEquals(tc, 0, ret); 57 | 58 | printf("test_starts_with_failed ok\n"); 59 | } 60 | 61 | void test_is_valid_ip(CuTest *tc) { 62 | int ret; 63 | 64 | ret = is_valid_ip("140.205.63.8"); 65 | CuAssertIntEquals(tc, 1, ret); 66 | 67 | printf("test_is_valid_ip ok\n"); 68 | } 69 | 70 | void test_oss_request_options_create_with_null_pool(CuTest *tc) { 71 | oss_request_options_t *option; 72 | option = oss_request_options_create(NULL); 73 | CuAssertTrue(tc, NULL != option); 74 | 75 | aos_pool_destroy(option->pool); 76 | 77 | printf("test_oss_request_options_create_with_null_pool ok\n"); 78 | } 79 | 80 | void test_oss_get_part_size(CuTest *tc) { 81 | int64_t file_size = 49999; 82 | int64_t part_size = 2; 83 | 84 | oss_get_part_size(file_size, &part_size); 85 | CuAssertIntEquals(tc, 5, part_size); 86 | 87 | printf("test_oss_get_part_size ok\n"); 88 | } 89 | 90 | void test_oss_get_object_uri_with_cname(CuTest *tc) { 91 | aos_pool_t *p; 92 | oss_request_options_t *options; 93 | aos_string_t bucket; 94 | aos_string_t object; 95 | aos_http_request_t req; 96 | 97 | aos_pool_create(&p, NULL); 98 | options = oss_request_options_create(p); 99 | options->config = oss_config_create(options->pool); 100 | options->config->is_cname = 1; 101 | aos_str_set(&options->config->endpoint, "img.abc.com"); 102 | 103 | aos_str_set(&bucket, "bucket-1"); 104 | aos_str_set(&object, "key-2"); 105 | 106 | oss_get_object_uri(options, &bucket, &object, &req); 107 | CuAssertStrEquals(tc, "", req.proto); 108 | CuAssertStrEquals(tc, "key-2", req.uri); 109 | CuAssertStrEquals(tc, "img.abc.com", req.host); 110 | 111 | aos_pool_destroy(p); 112 | 113 | printf("test_oss_get_object_uri_with_cname ok\n"); 114 | } 115 | 116 | void test_oss_get_object_uri_with_ip(CuTest *tc) { 117 | aos_pool_t *p; 118 | oss_request_options_t *options; 119 | aos_string_t bucket; 120 | aos_string_t object; 121 | aos_http_request_t req; 122 | 123 | aos_pool_create(&p, NULL); 124 | options = oss_request_options_create(p); 125 | options->config = oss_config_create(options->pool); 126 | options->config->is_cname = 0; 127 | aos_str_set(&options->config->endpoint, "http://140.205.63.8"); 128 | 129 | aos_str_set(&bucket, "bucket-1"); 130 | aos_str_set(&object, "key-2"); 131 | 132 | oss_get_object_uri(options, &bucket, &object, &req); 133 | CuAssertStrEquals(tc, "http://", req.proto); 134 | CuAssertStrEquals(tc, "bucket-1/key-2", req.uri); 135 | CuAssertStrEquals(tc, "140.205.63.8", req.host); 136 | 137 | aos_pool_destroy(p); 138 | 139 | printf("test_oss_get_object_uri_with_ip ok\n"); 140 | } 141 | 142 | void test_oss_get_bucket_uri_with_ip(CuTest *tc) { 143 | aos_pool_t *p; 144 | oss_request_options_t *options; 145 | aos_string_t bucket; 146 | aos_http_request_t req; 147 | 148 | aos_pool_create(&p, NULL); 149 | options = oss_request_options_create(p); 150 | options->config = oss_config_create(options->pool); 151 | options->config->is_cname = 0; 152 | aos_str_set(&options->config->endpoint, "140.205.63.8"); 153 | 154 | aos_str_set(&bucket, "bucket-1"); 155 | 156 | oss_get_bucket_uri(options, &bucket, &req); 157 | CuAssertStrEquals(tc, "", req.proto); 158 | CuAssertStrEquals(tc, "bucket-1", req.uri); 159 | CuAssertStrEquals(tc, "140.205.63.8", req.host); 160 | CuAssertStrEquals(tc, "bucket-1", req.resource); 161 | 162 | aos_pool_destroy(p); 163 | 164 | printf("test_oss_get_bucket_uri_with_ip ok\n"); 165 | } 166 | 167 | void test_oss_get_bucket_uri_with_cname(CuTest *tc) { 168 | aos_pool_t *p; 169 | oss_request_options_t *options; 170 | aos_string_t bucket; 171 | aos_http_request_t req; 172 | 173 | aos_pool_create(&p, NULL); 174 | options = oss_request_options_create(p); 175 | options->config = oss_config_create(options->pool); 176 | options->config->is_cname = 1; 177 | aos_str_set(&options->config->endpoint, "https://img.abc.com"); 178 | 179 | aos_str_set(&bucket, "bucket-1"); 180 | 181 | oss_get_bucket_uri(options, &bucket, &req); 182 | CuAssertStrEquals(tc, "https://", req.proto); 183 | CuAssertStrEquals(tc, "bucket-1", req.uri); 184 | CuAssertStrEquals(tc, "img.abc.com", req.host); 185 | CuAssertStrEquals(tc, "bucket-1/", req.resource); 186 | 187 | aos_pool_destroy(p); 188 | 189 | printf("test_oss_get_bucket_uri_with_cname ok\n"); 190 | } 191 | 192 | void test_aos_log_format_default(CuTest *tc) { 193 | /* 194 | * check is coredump 195 | */ 196 | aos_log_format_default(AOS_LOG_INFO, "/tmp/a", 10, "fun1", "%d-%d", 1, 2); 197 | 198 | printf("test_aos_log_format_default ok\n"); 199 | } 200 | 201 | void test_aos_log_print_default_with_null_file(CuTest *tc) { 202 | /* 203 | * check is coredump 204 | */ 205 | aos_stderr_file = NULL; 206 | aos_log_print_default("abc", 3); 207 | 208 | printf("test_aos_log_print_default_with_null_file ok\n"); 209 | } 210 | 211 | /* 212 | * aos_transport 213 | */ 214 | void test_aos_curl_code_to_status(CuTest *tc) { 215 | int code = aos_curl_code_to_status(CURLE_OUT_OF_MEMORY); 216 | CuAssertIntEquals(tc, AOSE_OUT_MEMORY, code); 217 | 218 | code = aos_curl_code_to_status(CURLE_COULDNT_RESOLVE_PROXY); 219 | CuAssertIntEquals(tc, AOSE_NAME_LOOKUP_ERROR, code); 220 | 221 | code = aos_curl_code_to_status(CURLE_COULDNT_RESOLVE_HOST); 222 | CuAssertIntEquals(tc, AOSE_NAME_LOOKUP_ERROR, code); 223 | 224 | code = aos_curl_code_to_status(CURLE_COULDNT_CONNECT); 225 | CuAssertIntEquals(tc, AOSE_FAILED_CONNECT, code); 226 | 227 | code = aos_curl_code_to_status(CURLE_WRITE_ERROR); 228 | CuAssertIntEquals(tc, AOSE_CONNECTION_FAILED, code); 229 | 230 | code = aos_curl_code_to_status(CURLE_OPERATION_TIMEDOUT); 231 | CuAssertIntEquals(tc, AOSE_CONNECTION_FAILED, code); 232 | 233 | code = aos_curl_code_to_status(CURLE_PARTIAL_FILE); 234 | CuAssertIntEquals(tc, AOSE_OK, code); 235 | 236 | code = aos_curl_code_to_status(CURLE_SSL_CACERT); 237 | CuAssertIntEquals(tc, AOSE_FAILED_VERIFICATION, code); 238 | 239 | code = aos_curl_code_to_status(CURLE_FTP_WEIRD_PASV_REPLY); 240 | CuAssertIntEquals(tc, AOSE_INTERNAL_ERROR, code); 241 | 242 | printf("test_aos_curl_code_to_status ok\n"); 243 | } 244 | 245 | /* 246 | * aos_string.h 247 | */ 248 | void test_aos_unquote_str(CuTest *tc) { 249 | aos_string_t str; 250 | aos_str_set(&str, "\"abc\""); 251 | aos_unquote_str(&str); 252 | 253 | CuAssertStrnEquals(tc, "abc", strlen("abc"), str.data); 254 | CuAssertIntEquals(tc, 3, str.len); 255 | 256 | printf("test_aos_unquote_str ok\n"); 257 | } 258 | 259 | void test_aos_ends_with(CuTest *tc) { 260 | int ret; 261 | aos_string_t str; 262 | aos_string_t suffix; 263 | 264 | aos_str_set(&str, "abc.mn.qp"); 265 | 266 | aos_str_set(&suffix, ".qp"); 267 | ret = aos_ends_with(&str, &suffix); 268 | CuAssertIntEquals(tc, 1, ret); 269 | 270 | aos_str_set(&suffix, ".mn"); 271 | ret = aos_ends_with(&str, &suffix); 272 | CuAssertIntEquals(tc, 0, ret); 273 | 274 | ret = aos_ends_with(&str, NULL); 275 | CuAssertIntEquals(tc, 0, ret); 276 | 277 | printf("test_aos_ends_with ok\n"); 278 | } 279 | 280 | /* 281 | * aos_util.h 282 | */ 283 | 284 | void test_aos_url_encode_failed(CuTest *tc) { 285 | int ret; 286 | char *dest; 287 | dest = (char*)malloc(20); 288 | 289 | ret = aos_url_encode(dest, "abc.xx.com", 1); 290 | CuAssertIntEquals(tc, AOSE_INVALID_ARGUMENT, ret); 291 | 292 | free(dest); 293 | 294 | printf("test_aos_url_encode_failed ok\n"); 295 | } 296 | 297 | void test_aos_url_encode_with_blank_char(CuTest *tc) { 298 | int ret; 299 | char *source; 300 | char *dest; 301 | source = "abc.xx.com/a b"; 302 | dest = (char*)malloc(20); 303 | 304 | ret = aos_url_encode(dest, source, strlen(source)); 305 | CuAssertIntEquals(tc, AOSE_OK, ret); 306 | CuAssertStrEquals(tc, "abc.xx.com/a%20b", dest); 307 | 308 | free(dest); 309 | 310 | printf("test_aos_url_encode_with_blank_char ok\n"); 311 | } 312 | 313 | void test_aos_url_decode_with_percent(CuTest *tc) { 314 | int ret; 315 | char *in; 316 | char *out; 317 | 318 | in = "abc.xx.com/a%20b"; 319 | out = (char*)malloc(20); 320 | 321 | ret = aos_url_decode(in, out); 322 | CuAssertIntEquals(tc, 0, ret); 323 | 324 | free(out); 325 | 326 | printf("test_aos_url_decode_with_percent ok\n"); 327 | } 328 | 329 | void test_aos_url_decode_with_add(CuTest *tc) { 330 | int ret; 331 | char *in; 332 | char *out; 333 | 334 | in = "abc.xx.com/a+b"; 335 | out = (char*)malloc(20); 336 | 337 | ret = aos_url_decode(in, out); 338 | CuAssertIntEquals(tc, 0, ret); 339 | 340 | free(out); 341 | 342 | printf("test_aos_url_decode_with_add ok\n"); 343 | } 344 | 345 | void test_aos_url_decode_failed(CuTest *tc) { 346 | int ret; 347 | char *in; 348 | char *out; 349 | 350 | in = "abc.xx.com/a%xb"; 351 | out = (char*)malloc(20); 352 | 353 | ret = aos_url_decode(in, out); 354 | CuAssertIntEquals(tc, -1, ret); 355 | 356 | free(out); 357 | 358 | printf("test_aos_url_decode_failed ok\n"); 359 | } 360 | 361 | CuSuite *test_aos() 362 | { 363 | CuSuite* suite = CuSuiteNew(); 364 | 365 | SUITE_ADD_TEST(suite, test_get_xml_doc_with_empty_aos_list); 366 | SUITE_ADD_TEST(suite, test_aos_list_movelist_with_empty_list); 367 | SUITE_ADD_TEST(suite, test_starts_with_failed); 368 | SUITE_ADD_TEST(suite, test_is_valid_ip); 369 | SUITE_ADD_TEST(suite, test_oss_request_options_create_with_null_pool); 370 | SUITE_ADD_TEST(suite, test_oss_get_part_size); 371 | SUITE_ADD_TEST(suite, test_oss_get_object_uri_with_cname); 372 | SUITE_ADD_TEST(suite, test_oss_get_object_uri_with_ip); 373 | SUITE_ADD_TEST(suite, test_oss_get_bucket_uri_with_cname); 374 | SUITE_ADD_TEST(suite, test_oss_get_bucket_uri_with_ip); 375 | SUITE_ADD_TEST(suite, test_aos_log_format_default); 376 | SUITE_ADD_TEST(suite, test_aos_log_print_default_with_null_file); 377 | SUITE_ADD_TEST(suite, test_aos_curl_code_to_status); 378 | SUITE_ADD_TEST(suite, test_aos_unquote_str); 379 | SUITE_ADD_TEST(suite, test_aos_ends_with); 380 | SUITE_ADD_TEST(suite, test_aos_url_encode_failed); 381 | SUITE_ADD_TEST(suite, test_aos_url_encode_with_blank_char); 382 | SUITE_ADD_TEST(suite, test_aos_url_decode_with_percent); 383 | SUITE_ADD_TEST(suite, test_aos_url_decode_with_add); 384 | SUITE_ADD_TEST(suite, test_aos_url_decode_failed); 385 | 386 | return suite; 387 | } 388 | -------------------------------------------------------------------------------- /test/CuTest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003 Asim Jalis 3 | * 4 | * This software is provided 'as-is', without any express or implied 5 | * warranty. In no event will the authors be held liable for any 6 | * damages arising from the use of this software. 7 | * 8 | * Permission is granted to anyone to use this software for any 9 | * purpose, including commercial applications, and to alter it and 10 | * redistribute it freely, subject to the following restrictions: 11 | * 12 | * 1. The origin of this software must not be misrepresented; you 13 | * must not claim that you wrote the original software. If you use 14 | * this software in a product, an acknowledgment in the product 15 | * documentation would be appreciated but is not required. 16 | * 17 | * 2. Altered source versions must be plainly marked as such, and 18 | * must not be misrepresented as being the original software. 19 | * 20 | * 3. This notice may not be removed or altered from any source 21 | * distribution. 22 | *-------------------------------------------------------------------------* 23 | * 24 | * Originally obtained from "http://cutest.sourceforge.net/" version 1.4. 25 | * 26 | * See CuTest.h for a list of serf-specific modifications. 27 | */ 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "CuTest.h" 36 | 37 | /*-------------------------------------------------------------------------* 38 | * CuStr 39 | *-------------------------------------------------------------------------*/ 40 | 41 | char* CuStrAlloc(int size) 42 | { 43 | char* newStr = (char*) malloc( sizeof(char) * (size) ); 44 | return newStr; 45 | } 46 | 47 | char* CuStrCopy(const char* old) 48 | { 49 | int len = strlen(old); 50 | char* newStr = CuStrAlloc(len + 1); 51 | strcpy(newStr, old); 52 | return newStr; 53 | } 54 | 55 | /*-------------------------------------------------------------------------* 56 | * CuString 57 | *-------------------------------------------------------------------------*/ 58 | 59 | void CuStringInit(CuString* str) 60 | { 61 | str->length = 0; 62 | str->size = STRING_MAX; 63 | str->buffer = (char*) malloc(sizeof(char) * str->size); 64 | str->buffer[0] = '\0'; 65 | } 66 | 67 | CuString* CuStringNew(void) 68 | { 69 | CuString* str = (CuString*) malloc(sizeof(CuString)); 70 | str->length = 0; 71 | str->size = STRING_MAX; 72 | str->buffer = (char*) malloc(sizeof(char) * str->size); 73 | str->buffer[0] = '\0'; 74 | return str; 75 | } 76 | 77 | void CuStringFree(CuString *str) 78 | { 79 | free(str->buffer); 80 | free(str); 81 | } 82 | 83 | void CuStringResize(CuString* str, int newSize) 84 | { 85 | str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); 86 | str->size = newSize; 87 | } 88 | 89 | void CuStringAppend(CuString* str, const char* text) 90 | { 91 | int length; 92 | 93 | if (text == NULL) { 94 | text = "NULL"; 95 | } 96 | 97 | length = strlen(text); 98 | if (str->length + length + 1 >= str->size) 99 | CuStringResize(str, str->length + length + 1 + STRING_INC); 100 | str->length += length; 101 | strcat(str->buffer, text); 102 | } 103 | 104 | void CuStringAppendChar(CuString* str, char ch) 105 | { 106 | char text[2]; 107 | text[0] = ch; 108 | text[1] = '\0'; 109 | CuStringAppend(str, text); 110 | } 111 | 112 | void CuStringAppendFormat(CuString* str, const char* format, ...) 113 | { 114 | va_list argp; 115 | char buf[HUGE_STRING_LEN]; 116 | va_start(argp, format); 117 | vsprintf(buf, format, argp); 118 | va_end(argp); 119 | CuStringAppend(str, buf); 120 | } 121 | 122 | void CuStringInsert(CuString* str, const char* text, int pos) 123 | { 124 | int length = strlen(text); 125 | if (pos > str->length) 126 | pos = str->length; 127 | if (str->length + length + 1 >= str->size) 128 | CuStringResize(str, str->length + length + 1 + STRING_INC); 129 | memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); 130 | str->length += length; 131 | memcpy(str->buffer + pos, text, length); 132 | } 133 | 134 | /*-------------------------------------------------------------------------* 135 | * CuTest 136 | *-------------------------------------------------------------------------*/ 137 | 138 | void CuTestInit(CuTest* t, const char* name, TestFunction function) 139 | { 140 | t->name = CuStrCopy(name); 141 | t->failed = 0; 142 | t->ran = 0; 143 | t->message = NULL; 144 | t->function = function; 145 | t->jumpBuf = NULL; 146 | t->setup = NULL; 147 | t->teardown = NULL; 148 | t->testBaton = NULL; 149 | } 150 | 151 | CuTest* CuTestNew(const char* name, TestFunction function) 152 | { 153 | CuTest* tc = CU_ALLOC(CuTest); 154 | CuTestInit(tc, name, function); 155 | return tc; 156 | } 157 | 158 | void CuTestFree(CuTest* tc) 159 | { 160 | free(tc->name); 161 | free(tc); 162 | } 163 | 164 | void CuTestRun(CuTest* tc) 165 | { 166 | jmp_buf buf; 167 | tc->jumpBuf = &buf; 168 | if (tc->setup) 169 | tc->testBaton = tc->setup(tc); 170 | if (setjmp(buf) == 0) 171 | { 172 | tc->ran = 1; 173 | (tc->function)(tc); 174 | } 175 | if (tc->teardown) 176 | tc->teardown(tc->testBaton); 177 | 178 | tc->jumpBuf = 0; 179 | } 180 | 181 | static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) 182 | { 183 | char buf[HUGE_STRING_LEN]; 184 | 185 | sprintf(buf, "%s:%d: ", file, line); 186 | CuStringInsert(string, buf, 0); 187 | 188 | tc->failed = 1; 189 | tc->message = string->buffer; 190 | if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); 191 | } 192 | 193 | void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) 194 | { 195 | CuString string; 196 | 197 | CuStringInit(&string); 198 | if (message2 != NULL) 199 | { 200 | CuStringAppend(&string, message2); 201 | CuStringAppend(&string, ": "); 202 | } 203 | CuStringAppend(&string, message); 204 | CuFailInternal(tc, file, line, &string); 205 | } 206 | 207 | void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) 208 | { 209 | if (condition) return; 210 | CuFail_Line(tc, file, line, NULL, message); 211 | } 212 | 213 | void CuAssertStrnEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 214 | const char* expected, size_t explen, 215 | const char* actual) 216 | { 217 | CuString string; 218 | if ((explen == 0) || 219 | (expected == NULL && actual == NULL) || 220 | (expected != NULL && actual != NULL && 221 | strncmp(expected, actual, explen) == 0)) 222 | { 223 | return; 224 | } 225 | 226 | CuStringInit(&string); 227 | if (message != NULL) 228 | { 229 | CuStringAppend(&string, message); 230 | CuStringAppend(&string, ": "); 231 | } 232 | CuStringAppend(&string, "expected <"); 233 | CuStringAppend(&string, expected); 234 | CuStringAppend(&string, "> but was <"); 235 | CuStringAppend(&string, actual); 236 | CuStringAppend(&string, ">"); 237 | CuFailInternal(tc, file, line, &string); 238 | } 239 | 240 | void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 241 | const char* expected, const char* actual) 242 | { 243 | CuString string; 244 | if ((expected == NULL && actual == NULL) || 245 | (expected != NULL && actual != NULL && 246 | strcmp(expected, actual) == 0)) 247 | { 248 | return; 249 | } 250 | 251 | CuStringInit(&string); 252 | if (message != NULL) 253 | { 254 | CuStringAppend(&string, message); 255 | CuStringAppend(&string, ": "); 256 | } 257 | CuStringAppend(&string, "expected <"); 258 | CuStringAppend(&string, expected); 259 | CuStringAppend(&string, "> but was <"); 260 | CuStringAppend(&string, actual); 261 | CuStringAppend(&string, ">"); 262 | CuFailInternal(tc, file, line, &string);} 263 | 264 | void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 265 | int expected, int actual) 266 | { 267 | char buf[STRING_MAX]; 268 | if (expected == actual) return; 269 | sprintf(buf, "expected <%d> but was <%d>", expected, actual); 270 | CuFail_Line(tc, file, line, message, buf); 271 | } 272 | 273 | void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 274 | double expected, double actual, double delta) 275 | { 276 | char buf[STRING_MAX]; 277 | if (fabs(expected - actual) <= delta) return; 278 | sprintf(buf, "expected <%lf> but was <%lf>", expected, actual); 279 | CuFail_Line(tc, file, line, message, buf); 280 | } 281 | 282 | void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 283 | void* expected, void* actual) 284 | { 285 | char buf[STRING_MAX]; 286 | if (expected == actual) return; 287 | sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual); 288 | CuFail_Line(tc, file, line, message, buf); 289 | } 290 | 291 | 292 | /*-------------------------------------------------------------------------* 293 | * CuSuite 294 | *-------------------------------------------------------------------------*/ 295 | 296 | void CuSuiteInit(CuSuite* testSuite) 297 | { 298 | testSuite->count = 0; 299 | testSuite->failCount = 0; 300 | testSuite->setup = NULL; 301 | testSuite->teardown = NULL; 302 | } 303 | 304 | CuSuite* CuSuiteNew(void) 305 | { 306 | CuSuite* testSuite = CU_ALLOC(CuSuite); 307 | CuSuiteInit(testSuite); 308 | return testSuite; 309 | } 310 | 311 | void CuSuiteFree(CuSuite *testSuite) 312 | { 313 | free(testSuite); 314 | } 315 | 316 | void CuSuiteFreeDeep(CuSuite *testSuite) 317 | { 318 | int i; 319 | for (i = 0 ; i < testSuite->count ; ++i) 320 | { 321 | CuTest* testCase = testSuite->list[i]; 322 | CuTestFree(testCase); 323 | } 324 | free(testSuite); 325 | } 326 | 327 | void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) 328 | { 329 | assert(testSuite->count < MAX_TEST_CASES); 330 | testSuite->list[testSuite->count] = testCase; 331 | testSuite->count++; 332 | 333 | /* CuSuiteAdd is called twice per test, don't reset the callbacks if 334 | already set. */ 335 | if (!testCase->setup) 336 | testCase->setup = testSuite->setup; 337 | if (!testCase->teardown) 338 | testCase->teardown = testSuite->teardown; 339 | } 340 | 341 | void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) 342 | { 343 | int i; 344 | for (i = 0 ; i < testSuite2->count ; ++i) 345 | { 346 | CuTest* testCase = testSuite2->list[i]; 347 | CuSuiteAdd(testSuite, testCase); 348 | } 349 | } 350 | 351 | void CuSuiteRun(CuSuite* testSuite) 352 | { 353 | int i; 354 | for (i = 0 ; i < testSuite->count ; ++i) 355 | { 356 | CuTest* testCase = testSuite->list[i]; 357 | CuTestRun(testCase); 358 | if (testCase->failed) { testSuite->failCount += 1; } 359 | } 360 | } 361 | 362 | void CuSuiteSummary(CuSuite* testSuite, CuString* summary) 363 | { 364 | int i; 365 | for (i = 0 ; i < testSuite->count ; ++i) 366 | { 367 | CuTest* testCase = testSuite->list[i]; 368 | CuStringAppend(summary, testCase->failed ? "F" : "."); 369 | } 370 | CuStringAppend(summary, "\n\n"); 371 | } 372 | 373 | void CuSuiteDetails(CuSuite* testSuite, CuString* details) 374 | { 375 | int i; 376 | int failCount = 0; 377 | 378 | if (testSuite->failCount == 0) 379 | { 380 | int passCount = testSuite->count - testSuite->failCount; 381 | const char* testWord = passCount == 1 ? "test" : "tests"; 382 | CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord); 383 | } 384 | else 385 | { 386 | if (testSuite->failCount == 1) 387 | CuStringAppend(details, "There was 1 failure:\n"); 388 | else 389 | CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount); 390 | 391 | for (i = 0 ; i < testSuite->count ; ++i) 392 | { 393 | CuTest* testCase = testSuite->list[i]; 394 | if (testCase->failed) 395 | { 396 | failCount++; 397 | CuStringAppendFormat(details, "%d) %s: %s\n", 398 | failCount, testCase->name, testCase->message); 399 | } 400 | } 401 | CuStringAppend(details, "\n!!!FAILURES!!!\n"); 402 | 403 | CuStringAppendFormat(details, "Runs: %d ", testSuite->count); 404 | CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount); 405 | CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount); 406 | } 407 | } 408 | 409 | void CuSuiteSetSetupTeardownCallbacks(CuSuite* testSuite, TestCallback setup, 410 | TestCallback teardown) 411 | { 412 | testSuite->setup = setup; 413 | testSuite->teardown = teardown; 414 | } 415 | -------------------------------------------------------------------------------- /src/oss_auth.c: -------------------------------------------------------------------------------- 1 | #include "oss_auth.h" 2 | #include "aos_log.h" 3 | #include "oss_util.h" 4 | 5 | static const char *g_s_oss_sub_resource_list[] = { 6 | "acl", 7 | "uploadId", 8 | "uploads", 9 | "partNumber", 10 | "response-content-type", 11 | "response-content-language", 12 | "response-expires", 13 | "response-cache-control", 14 | "response-content-disposition", 15 | "response-content-encoding", 16 | "append", 17 | "position", 18 | "lifecycle", 19 | "delete", 20 | NULL, 21 | }; 22 | 23 | static int is_oss_sub_resource(const char *str); 24 | static int is_oss_canonicalized_header(const char *str); 25 | static int oss_get_canonicalized_headers(aos_pool_t *p, 26 | const aos_table_t *headers, aos_buf_t *signbuf); 27 | static int oss_get_canonicalized_resource(aos_pool_t *p, 28 | const aos_table_t *params, aos_buf_t *signbuf); 29 | 30 | static int is_oss_sub_resource(const char *str) 31 | { 32 | int i = 0; 33 | for ( ; g_s_oss_sub_resource_list[i]; i++) { 34 | if (apr_strnatcmp(g_s_oss_sub_resource_list[i], str) == 0) { 35 | return 1; 36 | } 37 | } 38 | return 0; 39 | } 40 | 41 | static int is_oss_canonicalized_header(const char *str) 42 | { 43 | size_t len = strlen(OSS_CANNONICALIZED_HEADER_PREFIX); 44 | return strncasecmp(str, OSS_CANNONICALIZED_HEADER_PREFIX, len) == 0; 45 | } 46 | 47 | static int oss_get_canonicalized_headers(aos_pool_t *p, 48 | const aos_table_t *headers, 49 | aos_buf_t *signbuf) 50 | { 51 | int pos; 52 | int meta_count = 0; 53 | int i; 54 | int len; 55 | const aos_array_header_t *tarr; 56 | const aos_table_entry_t *telts; 57 | char **meta_headers; 58 | const char *value; 59 | aos_string_t tmp_str; 60 | char tmpbuf[AOS_MAX_QUERY_ARG_LEN+1]; 61 | 62 | if (apr_is_empty_table(headers)) { 63 | return AOSE_OK; 64 | } 65 | 66 | // sort user meta header 67 | tarr = aos_table_elts(headers); 68 | telts = (aos_table_entry_t*)tarr->elts; 69 | meta_headers = aos_pcalloc(p, tarr->nelts * sizeof(char*)); 70 | for (pos = 0; pos < tarr->nelts; ++pos) { 71 | if (is_oss_canonicalized_header(telts[pos].key)) { 72 | aos_string_t key = aos_string(telts[pos].key); 73 | aos_string_tolower(&key); 74 | meta_headers[meta_count++] = key.data; 75 | } 76 | } 77 | if (meta_count == 0) { 78 | return AOSE_OK; 79 | } 80 | aos_gnome_sort((const char **)meta_headers, meta_count); 81 | 82 | // sign string 83 | for (i = 0; i < meta_count; ++i) { 84 | value = apr_table_get(headers, meta_headers[i]); 85 | aos_str_set(&tmp_str, value); 86 | aos_strip_space(&tmp_str); 87 | len = apr_snprintf(tmpbuf, sizeof(tmpbuf), "%s:%.*s", 88 | meta_headers[i], tmp_str.len, tmp_str.data); 89 | if (len >= AOS_MAX_HEADER_LEN) { 90 | aos_error_log("user meta header too many, %s.", tmpbuf); 91 | return AOSE_INVALID_ARGUMENT; 92 | } 93 | tmp_str.data = tmpbuf; 94 | tmp_str.len = len; 95 | aos_buf_append_string(p, signbuf, tmpbuf, len); 96 | aos_buf_append_string(p, signbuf, "\n", sizeof("\n")-1); 97 | } 98 | 99 | return AOSE_OK; 100 | } 101 | 102 | static int oss_get_canonicalized_resource(aos_pool_t *p, 103 | const aos_table_t *params, 104 | aos_buf_t *signbuf) 105 | { 106 | int pos; 107 | int subres_count = 0; 108 | int i; 109 | int len; 110 | char sep; 111 | const char *value; 112 | char tmpbuf[AOS_MAX_QUERY_ARG_LEN+1]; 113 | char **subres_headers; 114 | const aos_array_header_t *tarr; 115 | const aos_table_entry_t *telts; 116 | 117 | if (apr_is_empty_table(params)) { 118 | return AOSE_OK; 119 | } 120 | 121 | // sort sub resource param 122 | tarr = aos_table_elts(params); 123 | telts = (aos_table_entry_t*)tarr->elts; 124 | subres_headers = aos_pcalloc(p, tarr->nelts * sizeof(char*)); 125 | for (pos = 0; pos < tarr->nelts; ++pos) { 126 | if (is_oss_sub_resource(telts[pos].key)) { 127 | subres_headers[subres_count++] = telts[pos].key; 128 | } 129 | } 130 | if (subres_count == 0) { 131 | return AOSE_OK; 132 | } 133 | aos_gnome_sort((const char **)subres_headers, subres_count); 134 | 135 | // sign string 136 | sep = '?'; 137 | for (i = 0; i < subres_count; ++i) { 138 | value = apr_table_get(params, subres_headers[i]); 139 | if (value != NULL && *value != '\0') { 140 | len = apr_snprintf(tmpbuf, sizeof(tmpbuf), "%c%s=%s", 141 | sep, subres_headers[i], value); 142 | } else { 143 | len = apr_snprintf(tmpbuf, sizeof(tmpbuf), "%c%s", 144 | sep, subres_headers[i]); 145 | } 146 | if (len >= AOS_MAX_QUERY_ARG_LEN) { 147 | aos_error_log("http query params too long, %s.", tmpbuf); 148 | return AOSE_INVALID_ARGUMENT; 149 | } 150 | aos_buf_append_string(p, signbuf, tmpbuf, len); 151 | sep = '&'; 152 | } 153 | 154 | return AOSE_OK; 155 | } 156 | 157 | int oss_get_string_to_sign(aos_pool_t *p, 158 | http_method_e method, 159 | const aos_string_t *canon_res, 160 | const aos_table_t *headers, 161 | const aos_table_t *params, 162 | aos_string_t *signstr) 163 | { 164 | int res; 165 | aos_buf_t *signbuf; 166 | const char *value; 167 | aos_str_null(signstr); 168 | 169 | signbuf = aos_create_buf(p, 1024); 170 | 171 | #define signbuf_append_from_headers(KEY) do { \ 172 | if ((value = apr_table_get(headers, KEY)) != NULL) { \ 173 | aos_buf_append_string(p, signbuf, value, strlen(value)); \ 174 | } \ 175 | aos_buf_append_string(p, signbuf, "\n", sizeof("\n")-1); \ 176 | } while (0) 177 | 178 | #define signbuf_append(VALUE, LEN) do { \ 179 | aos_buf_append_string(p, signbuf, VALUE, LEN); \ 180 | aos_buf_append_string(p, signbuf, "\n", sizeof("\n")-1); \ 181 | } while (0) 182 | 183 | value = aos_http_method_to_string(method); 184 | signbuf_append(value, strlen(value)); 185 | 186 | signbuf_append_from_headers(OSS_CONTENT_MD5); 187 | signbuf_append_from_headers(OSS_CONTENT_TYPE); 188 | 189 | // date 190 | if ((value = apr_table_get(headers, OSS_CANNONICALIZED_HEADER_DATE)) == NULL) { 191 | value = apr_table_get(headers, OSS_DATE); 192 | } 193 | if (NULL == value || *value == '\0') { 194 | aos_error_log("http header date is empty."); 195 | return AOSE_INVALID_ARGUMENT; 196 | } 197 | signbuf_append(value, strlen(value)); 198 | 199 | // user meta headers 200 | if ((res = oss_get_canonicalized_headers(p, headers, signbuf)) != AOSE_OK) { 201 | return res; 202 | } 203 | 204 | // canonicalized resource 205 | aos_buf_append_string(p, signbuf, canon_res->data, canon_res->len); 206 | 207 | if (params != NULL && (res = oss_get_canonicalized_resource(p, params, signbuf)) != AOSE_OK) { 208 | return res; 209 | } 210 | 211 | // result 212 | signstr->data = (char *)signbuf->pos; 213 | signstr->len = aos_buf_size(signbuf); 214 | 215 | return AOSE_OK; 216 | } 217 | 218 | void oss_sign_headers(aos_pool_t *p, 219 | const aos_string_t *signstr, 220 | const aos_string_t *access_key_id, 221 | const aos_string_t *access_key_secret, 222 | aos_table_t *headers) 223 | { 224 | int b64Len; 225 | char *value; 226 | unsigned char hmac[20]; 227 | char b64[((20 + 1) * 4) / 3]; 228 | 229 | HMAC_SHA1(hmac, (unsigned char *)access_key_secret->data, access_key_secret->len, 230 | (unsigned char *)signstr->data, signstr->len); 231 | 232 | // Now base-64 encode the results 233 | b64Len = aos_base64_encode(hmac, 20, b64); 234 | value = apr_psprintf(p, "OSS %.*s:%.*s", access_key_id->len, access_key_id->data, b64Len, b64); 235 | apr_table_addn(headers, OSS_AUTHORIZATION, value); 236 | 237 | return; 238 | } 239 | 240 | int oss_get_signed_headers(aos_pool_t *p, 241 | const aos_string_t *access_key_id, 242 | const aos_string_t *access_key_secret, 243 | const aos_string_t* canon_res, 244 | aos_http_request_t *req) 245 | { 246 | int res; 247 | aos_string_t signstr; 248 | 249 | res = oss_get_string_to_sign(p, req->method, canon_res, 250 | req->headers, req->query_params, &signstr); 251 | 252 | if (res != AOSE_OK) { 253 | return res; 254 | } 255 | 256 | aos_debug_log("signstr:%.*s.", signstr.len, signstr.data); 257 | 258 | oss_sign_headers(p, &signstr, access_key_id, access_key_secret, req->headers); 259 | 260 | return AOSE_OK; 261 | } 262 | 263 | int oss_sign_request(aos_http_request_t *req, 264 | const oss_config_t *config) 265 | { 266 | aos_string_t canon_res; 267 | char canon_buf[AOS_MAX_URI_LEN]; 268 | char datestr[AOS_MAX_GMT_TIME_LEN]; 269 | const char *value; 270 | int res = AOSE_OK; 271 | int len = 0; 272 | 273 | len = strlen(req->resource); 274 | if (len >= AOS_MAX_URI_LEN - 1) { 275 | aos_error_log("http resource too long, %s.", req->resource); 276 | return AOSE_INVALID_ARGUMENT; 277 | } 278 | 279 | canon_res.data = canon_buf; 280 | canon_res.len = apr_snprintf(canon_buf, sizeof(canon_buf), "/%s", req->resource); 281 | 282 | if ((value = apr_table_get(req->headers, OSS_CANNONICALIZED_HEADER_DATE)) == NULL) { 283 | aos_get_gmt_str_time(datestr); 284 | apr_table_set(req->headers, OSS_DATE, datestr); 285 | } 286 | 287 | res = oss_get_signed_headers(req->pool, &config->access_key_id, 288 | &config->access_key_secret, &canon_res, req); 289 | return res; 290 | } 291 | 292 | int get_oss_request_signature(const oss_request_options_t *options, 293 | aos_http_request_t *req, 294 | const aos_string_t *expires, 295 | aos_string_t *signature) 296 | { 297 | aos_string_t canon_res; 298 | char canon_buf[AOS_MAX_URI_LEN]; 299 | const char *value; 300 | aos_string_t signstr; 301 | int res = AOSE_OK; 302 | int b64Len; 303 | unsigned char hmac[20]; 304 | char b64[((20 + 1) * 4) / 3]; 305 | 306 | canon_res.data = canon_buf; 307 | canon_res.len = apr_snprintf(canon_buf, sizeof(canon_buf), "/%s", req->resource); 308 | 309 | apr_table_set(req->headers, OSS_DATE, expires->data); 310 | 311 | if ((res = oss_get_string_to_sign(options->pool, req->method, &canon_res, 312 | req->headers, req->query_params, &signstr))!= AOSE_OK) { 313 | return res; 314 | } 315 | 316 | HMAC_SHA1(hmac, (unsigned char *)options->config->access_key_secret.data, 317 | options->config->access_key_secret.len, 318 | (unsigned char *)signstr.data, signstr.len); 319 | 320 | b64Len = aos_base64_encode(hmac, 20, b64); 321 | value = apr_psprintf(options->pool, "%.*s", b64Len, b64); 322 | aos_str_set(signature, value); 323 | 324 | return res; 325 | } 326 | 327 | int oss_get_signed_url(const oss_request_options_t *options, 328 | aos_http_request_t *req, 329 | const aos_string_t *expires, 330 | aos_string_t *signed_url) 331 | { 332 | char *signed_url_str; 333 | aos_string_t querystr; 334 | char uristr[3*AOS_MAX_URI_LEN+1]; 335 | int res = AOSE_OK; 336 | aos_string_t signature; 337 | const char *proto; 338 | 339 | res = get_oss_request_signature(options, req, expires, &signature); 340 | if (res != AOSE_OK) { 341 | return res; 342 | } 343 | 344 | apr_table_set(req->query_params, OSS_ACCESSKEYID, 345 | options->config->access_key_id.data); 346 | apr_table_set(req->query_params, OSS_EXPIRES, expires->data); 347 | apr_table_set(req->query_params, OSS_SIGNATURE, signature.data); 348 | 349 | uristr[0] = '\0'; 350 | aos_str_null(&querystr); 351 | res = aos_url_encode(uristr, req->uri, AOS_MAX_URI_LEN); 352 | if (res != AOSE_OK) { 353 | return res; 354 | } 355 | 356 | res = aos_query_params_to_string(options->pool, req->query_params, &querystr); 357 | if (res != AOSE_OK) { 358 | return res; 359 | } 360 | 361 | proto = strlen(req->proto) != 0 ? req->proto : AOS_HTTP_PREFIX; 362 | signed_url_str = apr_psprintf(options->pool, "%s%s/%s%.*s", 363 | proto, req->host, uristr, 364 | querystr.len, querystr.data); 365 | aos_str_set(signed_url, signed_url_str); 366 | 367 | return res; 368 | } 369 | -------------------------------------------------------------------------------- /src/oss_bucket.c: -------------------------------------------------------------------------------- 1 | #include "aos_log.h" 2 | #include "aos_define.h" 3 | #include "aos_util.h" 4 | #include "aos_string.h" 5 | #include "aos_status.h" 6 | #include "oss_auth.h" 7 | #include "oss_util.h" 8 | #include "oss_xml.h" 9 | #include "oss_api.h" 10 | 11 | aos_status_t *oss_create_bucket(const oss_request_options_t *options, 12 | const aos_string_t *bucket, 13 | oss_acl_e oss_acl, 14 | aos_table_t **resp_headers) 15 | { 16 | const char *oss_acl_str = NULL; 17 | aos_status_t *s = NULL; 18 | aos_http_request_t *req = NULL; 19 | aos_http_response_t *resp = NULL; 20 | aos_table_t *headers = NULL; 21 | aos_table_t *query_params = NULL; 22 | 23 | query_params = aos_table_create_if_null(options, query_params, 0); 24 | 25 | //init headers 26 | headers = aos_table_create_if_null(options, headers, 1); 27 | oss_acl_str = get_oss_acl_str(oss_acl); 28 | if (oss_acl_str) { 29 | apr_table_set(headers, OSS_CANNONICALIZED_HEADER_ACL, oss_acl_str); 30 | } 31 | 32 | oss_init_bucket_request(options, bucket, HTTP_PUT, &req, 33 | query_params, headers, &resp); 34 | 35 | s = oss_process_request(options, req, resp); 36 | *resp_headers = resp->headers; 37 | 38 | return s; 39 | } 40 | 41 | aos_status_t *oss_delete_bucket(const oss_request_options_t *options, 42 | const aos_string_t *bucket, 43 | aos_table_t **resp_headers) 44 | { 45 | aos_status_t *s = NULL; 46 | aos_http_request_t *req = NULL; 47 | aos_http_response_t *resp = NULL; 48 | aos_table_t *query_params = NULL; 49 | aos_table_t *headers = NULL; 50 | 51 | headers = aos_table_create_if_null(options, headers, 0); 52 | query_params = aos_table_create_if_null(options, query_params, 0); 53 | 54 | oss_init_bucket_request(options, bucket, HTTP_DELETE, &req, 55 | query_params, headers, &resp); 56 | 57 | s = oss_process_request(options, req, resp); 58 | *resp_headers = resp->headers; 59 | 60 | return s; 61 | } 62 | 63 | aos_status_t *oss_put_bucket_acl(const oss_request_options_t *options, 64 | const aos_string_t *bucket, 65 | oss_acl_e oss_acl, 66 | aos_table_t **resp_headers) 67 | { 68 | aos_status_t *s = NULL; 69 | aos_http_request_t *req = NULL; 70 | aos_http_response_t *resp = NULL; 71 | aos_table_t *query_params = NULL; 72 | aos_table_t *headers = NULL; 73 | const char *oss_acl_str = NULL; 74 | 75 | query_params = aos_table_create_if_null(options, query_params, 1); 76 | apr_table_add(query_params, OSS_ACL, ""); 77 | 78 | headers = aos_table_create_if_null(options, headers, 1); 79 | oss_acl_str = get_oss_acl_str(oss_acl); 80 | if (oss_acl_str) { 81 | apr_table_set(headers, OSS_CANNONICALIZED_HEADER_ACL, oss_acl_str); 82 | } 83 | 84 | oss_init_bucket_request(options, bucket, HTTP_PUT, &req, 85 | query_params, headers, &resp); 86 | 87 | s = oss_process_request(options, req, resp); 88 | *resp_headers = resp->headers; 89 | 90 | return s; 91 | } 92 | 93 | aos_status_t *oss_get_bucket_acl(const oss_request_options_t *options, 94 | const aos_string_t *bucket, 95 | aos_string_t *oss_acl, 96 | aos_table_t **resp_headers) 97 | { 98 | aos_status_t *s = NULL; 99 | int res; 100 | aos_http_request_t *req = NULL; 101 | aos_http_response_t *resp = NULL; 102 | aos_table_t *query_params = NULL; 103 | aos_table_t *headers = NULL; 104 | 105 | query_params = aos_table_create_if_null(options, query_params, 1); 106 | apr_table_add(query_params, OSS_ACL, ""); 107 | 108 | headers = aos_table_create_if_null(options, headers, 0); 109 | 110 | oss_init_bucket_request(options, bucket, HTTP_GET, &req, 111 | query_params, headers, &resp); 112 | 113 | s = oss_process_request(options, req, resp); 114 | *resp_headers = resp->headers; 115 | if (!aos_status_is_ok(s)) { 116 | return s; 117 | } 118 | 119 | res = oss_acl_parse_from_body(options->pool, &resp->body, oss_acl); 120 | if (res != AOSE_OK) { 121 | aos_xml_error_status_set(s, res); 122 | } 123 | 124 | return s; 125 | } 126 | 127 | aos_status_t *oss_list_object(const oss_request_options_t *options, 128 | const aos_string_t *bucket, 129 | oss_list_object_params_t *params, 130 | aos_table_t **resp_headers) 131 | { 132 | int res; 133 | aos_status_t *s = NULL; 134 | aos_http_request_t *req = NULL; 135 | aos_http_response_t *resp = NULL; 136 | aos_table_t *query_params = NULL; 137 | aos_table_t *headers = NULL; 138 | 139 | //init query_params 140 | query_params = aos_table_create_if_null(options, query_params, 4); 141 | apr_table_add(query_params, OSS_PREFIX, params->prefix.data); 142 | apr_table_add(query_params, OSS_DELIMITER, params->delimiter.data); 143 | apr_table_add(query_params, OSS_MARKER, params->marker.data); 144 | aos_table_add_int(query_params, OSS_MAX_KEYS, params->max_ret); 145 | 146 | //init headers 147 | headers = aos_table_create_if_null(options, headers, 0); 148 | 149 | oss_init_bucket_request(options, bucket, HTTP_GET, &req, 150 | query_params, headers, &resp); 151 | 152 | s = oss_process_request(options, req, resp); 153 | *resp_headers = resp->headers; 154 | if (!aos_status_is_ok(s)) { 155 | return s; 156 | } 157 | 158 | res = oss_list_objects_parse_from_body(options->pool, &resp->body, 159 | ¶ms->object_list, ¶ms->common_prefix_list, 160 | ¶ms->next_marker, ¶ms->truncated); 161 | if (res != AOSE_OK) { 162 | aos_xml_error_status_set(s, res); 163 | } 164 | 165 | return s; 166 | } 167 | 168 | aos_status_t *oss_put_bucket_lifecycle(const oss_request_options_t *options, 169 | const aos_string_t *bucket, 170 | aos_list_t *lifecycle_rule_list, 171 | aos_table_t **resp_headers) 172 | { 173 | aos_status_t *s = NULL; 174 | aos_http_request_t *req = NULL; 175 | aos_http_response_t *resp = NULL; 176 | apr_table_t *query_params = NULL; 177 | aos_table_t *headers = NULL; 178 | aos_list_t body; 179 | 180 | //init query_params 181 | query_params = aos_table_create_if_null(options, query_params, 1); 182 | apr_table_add(query_params, OSS_LIFECYCLE, ""); 183 | 184 | //init headers 185 | headers = aos_table_create_if_null(options, headers, 0); 186 | 187 | oss_init_bucket_request(options, bucket, HTTP_PUT, &req, 188 | query_params, headers, &resp); 189 | 190 | build_lifecycle_body(options->pool, lifecycle_rule_list, &body); 191 | oss_write_request_body_from_buffer(&body, req); 192 | s = oss_process_request(options, req, resp); 193 | *resp_headers = resp->headers; 194 | 195 | return s; 196 | } 197 | 198 | aos_status_t *oss_get_bucket_lifecycle(const oss_request_options_t *options, 199 | const aos_string_t *bucket, 200 | aos_list_t *lifecycle_rule_list, 201 | aos_table_t **resp_headers) 202 | { 203 | int res; 204 | aos_status_t *s = NULL; 205 | aos_http_request_t *req = NULL; 206 | aos_http_response_t *resp = NULL; 207 | aos_table_t *query_params = NULL; 208 | aos_table_t *headers = NULL; 209 | 210 | //init query_params 211 | query_params = aos_table_create_if_null(options, query_params, 1); 212 | apr_table_add(query_params, OSS_LIFECYCLE, ""); 213 | 214 | //init headers 215 | headers = aos_table_create_if_null(options, headers, 0); 216 | 217 | oss_init_bucket_request(options, bucket, HTTP_GET, &req, 218 | query_params, headers, &resp); 219 | 220 | s = oss_process_request(options, req, resp); 221 | *resp_headers = resp->headers; 222 | if (!aos_status_is_ok(s)) { 223 | return s; 224 | } 225 | 226 | res = oss_lifecycle_rules_parse_from_body(options->pool, 227 | &resp->body, lifecycle_rule_list); 228 | if (res != AOSE_OK) { 229 | aos_xml_error_status_set(s, res); 230 | } 231 | 232 | return s; 233 | } 234 | 235 | aos_status_t *oss_delete_bucket_lifecycle(const oss_request_options_t *options, 236 | const aos_string_t *bucket, 237 | aos_table_t **resp_headers) 238 | { 239 | aos_status_t *s = NULL; 240 | aos_http_request_t *req = NULL; 241 | aos_http_response_t *resp = NULL; 242 | aos_table_t *query_params = NULL; 243 | aos_table_t *headers = NULL; 244 | 245 | //init query_params 246 | query_params = aos_table_create_if_null(options, query_params, 1); 247 | apr_table_add(query_params, OSS_LIFECYCLE, ""); 248 | 249 | //init headers 250 | headers = aos_table_create_if_null(options, headers, 0); 251 | 252 | oss_init_bucket_request(options, bucket, HTTP_DELETE, &req, 253 | query_params, headers, &resp); 254 | 255 | s = oss_process_request(options, req, resp); 256 | *resp_headers = resp->headers; 257 | 258 | return s; 259 | } 260 | 261 | aos_status_t *oss_delete_objects(const oss_request_options_t *options, 262 | const aos_string_t *bucket, 263 | aos_list_t *object_list, 264 | int is_quiet, 265 | aos_table_t **resp_headers, 266 | aos_list_t *deleted_object_list) 267 | { 268 | int res; 269 | aos_status_t *s = NULL; 270 | aos_http_request_t *req = NULL; 271 | aos_http_response_t *resp = NULL; 272 | aos_table_t *headers = NULL; 273 | aos_table_t *query_params = NULL; 274 | aos_list_t body; 275 | unsigned char *md5 = NULL; 276 | char *buf = NULL; 277 | int64_t body_len; 278 | char *b64_value = NULL; 279 | int b64_buf_len = (20 + 1) * 4 / 3; 280 | int b64_len; 281 | 282 | //init query_params 283 | query_params = aos_table_create_if_null(options, query_params, 1); 284 | apr_table_add(query_params, OSS_DELETE, ""); 285 | 286 | //init headers 287 | headers = aos_table_create_if_null(options, headers, 1); 288 | apr_table_set(headers, OSS_CONTENT_TYPE, OSS_MULTIPART_CONTENT_TYPE); 289 | 290 | oss_init_bucket_request(options, bucket, HTTP_POST, &req, 291 | query_params, headers, &resp); 292 | 293 | build_delete_objects_body(options->pool, object_list, is_quiet, &body); 294 | 295 | //add Content-MD5 296 | body_len = aos_buf_list_len(&body); 297 | buf = aos_buf_list_content(options->pool, &body); 298 | md5 = aos_md5(options->pool, buf, body_len); 299 | b64_value = aos_pcalloc(options->pool, b64_buf_len); 300 | b64_len = aos_base64_encode(md5, 20, b64_value); 301 | b64_value[b64_len] = '\0'; 302 | apr_table_addn(headers, OSS_CONTENT_MD5, b64_value); 303 | 304 | oss_write_request_body_from_buffer(&body, req); 305 | 306 | s = oss_process_request(options, req, resp); 307 | *resp_headers = resp->headers; 308 | 309 | if (is_quiet) { 310 | return s; 311 | } 312 | 313 | if (!aos_status_is_ok(s)) { 314 | return s; 315 | } 316 | 317 | res = oss_delete_objects_parse_from_body(options->pool, &resp->body, 318 | deleted_object_list); 319 | if (res != AOSE_OK) { 320 | aos_xml_error_status_set(s, res); 321 | } 322 | 323 | return s; 324 | } 325 | 326 | aos_status_t *oss_delete_objects_by_prefix(oss_request_options_t *options, 327 | const aos_string_t *bucket, 328 | const aos_string_t *prefix) 329 | { 330 | aos_pool_t *subpool = NULL; 331 | aos_pool_t *parent_pool = NULL; 332 | int is_quiet = 1; 333 | aos_status_t *s = NULL; 334 | aos_status_t *ret = NULL; 335 | oss_list_object_params_t *params = NULL; 336 | int list_object_count = 0; 337 | 338 | parent_pool = options->pool; 339 | params = oss_create_list_object_params(parent_pool); 340 | if (prefix->data == NULL) { 341 | aos_str_set(¶ms->prefix, ""); 342 | } else { 343 | aos_str_set(¶ms->prefix, prefix->data); 344 | } 345 | while (params->truncated) { 346 | aos_table_t *list_object_resp_headers = NULL; 347 | aos_list_t object_list; 348 | aos_list_t deleted_object_list; 349 | oss_list_object_content_t *list_content = NULL; 350 | aos_table_t *delete_objects_resp_headers = NULL; 351 | char *key = NULL; 352 | 353 | aos_pool_create(&subpool, parent_pool); 354 | options->pool = subpool; 355 | list_object_count = 0; 356 | aos_list_init(&object_list); 357 | s = oss_list_object(options, bucket, params, &list_object_resp_headers); 358 | if (!aos_status_is_ok(s)) { 359 | ret = aos_status_dup(parent_pool, s); 360 | aos_pool_destroy(subpool); 361 | options->pool = parent_pool; 362 | return ret; 363 | } 364 | 365 | aos_list_for_each_entry(list_content, ¶ms->object_list, node) { 366 | oss_object_key_t *object_key = oss_create_oss_object_key(parent_pool); 367 | key = apr_psprintf(parent_pool, "%.*s", list_content->key.len, 368 | list_content->key.data); 369 | aos_str_set(&object_key->key, key); 370 | aos_list_add_tail(&object_key->node, &object_list); 371 | list_object_count += 1; 372 | } 373 | if (list_object_count == 0) 374 | { 375 | ret = aos_status_dup(parent_pool, s); 376 | aos_pool_destroy(subpool); 377 | options->pool = parent_pool; 378 | return ret; 379 | } 380 | aos_pool_destroy(subpool); 381 | 382 | aos_list_init(&deleted_object_list); 383 | aos_pool_create(&subpool, parent_pool); 384 | options->pool = subpool; 385 | s = oss_delete_objects(options, bucket, &object_list, is_quiet, 386 | &delete_objects_resp_headers, &deleted_object_list); 387 | if (!aos_status_is_ok(s)) { 388 | ret = aos_status_dup(parent_pool, s); 389 | aos_pool_destroy(subpool); 390 | options->pool = parent_pool; 391 | return ret; 392 | } 393 | if (!params->truncated) { 394 | ret = aos_status_dup(parent_pool, s); 395 | } 396 | 397 | aos_pool_destroy(subpool); 398 | 399 | aos_list_init(¶ms->object_list); 400 | if (params->next_marker.data) { 401 | aos_str_set(¶ms->marker, params->next_marker.data); 402 | } 403 | } 404 | options->pool = parent_pool; 405 | return ret; 406 | } 407 | --------------------------------------------------------------------------------