HTTP and HTTPS library for Mbed OS 5

Dependents:   MQTTGateway2 MQTTGatewayK64 http-example-wnc GuardRoom ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  * PackageLicenseDeclared: Apache-2.0
00003  * Copyright (c) 2018 ARM Limited
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "mbed.h"
00019 #include "http_request.h"
00020 #include "https_request.h"
00021 #include "test_setup.h"
00022 #include "utest/utest.h"
00023 #include "unity/unity.h"
00024 #include "greentea-client/test_env.h"
00025 
00026 using namespace utest::v1;
00027 
00028 static NetworkInterface *network;
00029 
00030 static void setup_verify_network() {
00031     if (!network) network = connect_to_default_network_interface();
00032     TEST_ASSERT_NOT_NULL(network);
00033 }
00034 
00035 // verifies that the header is present and has a certain value
00036 static void assert_header(HttpResponse *res, const char *header, const char *value) {
00037     bool headerPresent = false;
00038     for (size_t ix = 0; ix < res->get_headers_length(); ix++) {
00039         if (res->get_headers_fields()[ix]->compare(header)) {
00040             headerPresent = true;
00041 
00042             TEST_ASSERT(res->get_headers_values()[ix]->compare(value));
00043         }
00044     }
00045     TEST_ASSERT_EQUAL(true, headerPresent);
00046 }
00047 
00048 static control_t http_get(const size_t call_count) {
00049     setup_verify_network();
00050 
00051     HttpRequest *req = new HttpRequest(network, HTTP_GET, "http://httpbin.org/status/418");
00052 
00053     HttpResponse* res = req->send();
00054     TEST_ASSERT(res);
00055     TEST_ASSERT_EQUAL(418, res->get_status_code());
00056 
00057     delete req;
00058 
00059     return CaseNext;
00060 }
00061 
00062 static control_t http_post(const size_t call_count) {
00063     setup_verify_network();
00064 
00065     HttpRequest* req = new HttpRequest(network, HTTP_POST, "http://httpbin.org/post");
00066     req->set_header("Content-Type", "application/json");
00067 
00068     const char body[] = "{\"mykey\":\"mbedvalue\"}";
00069 
00070     HttpResponse* res = req->send(body, strlen(body));
00071     TEST_ASSERT(res);
00072     TEST_ASSERT_EQUAL(200, res->get_status_code());
00073 
00074     // verify that the Content-Type header is present, and set to application/json
00075     assert_header(res, "Content-Type", "application/json");
00076 
00077     // verify that both the key and value are present in the response
00078     TEST_ASSERT(res->get_body_length() > 0);
00079     TEST_ASSERT_NOT_EQUAL(res->get_body_as_string().find("mykey"), string::npos);
00080     TEST_ASSERT_NOT_EQUAL(res->get_body_as_string().find("mbedvalue"), string::npos);
00081 
00082     delete req;
00083 
00084     return CaseNext;
00085 }
00086 
00087 static control_t http_socket_reuse(const size_t call_count) {
00088     setup_verify_network();
00089 
00090     TCPSocket socket;
00091     nsapi_error_t open_result = socket.open(network);
00092     TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, open_result);
00093 
00094     nsapi_error_t connect_result = socket.connect("httpbin.org", 80);
00095     TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, connect_result);
00096 
00097     {
00098         HttpRequest *req = new HttpRequest(&socket, HTTP_GET, "http://httpbin.org/status/404");
00099 
00100         HttpResponse* res = req->send();
00101         TEST_ASSERT(res);
00102         TEST_ASSERT_EQUAL(404, res->get_status_code());
00103 
00104         delete req;
00105     }
00106 
00107     {
00108         HttpRequest *req = new HttpRequest(&socket, HTTP_GET, "http://httpbin.org/status/403");
00109 
00110         HttpResponse* res = req->send();
00111         TEST_ASSERT(res);
00112         TEST_ASSERT_EQUAL(403, res->get_status_code());
00113 
00114         delete req;
00115     }
00116 
00117     return CaseNext;
00118 }
00119 
00120 static control_t https_get(const size_t call_count) {
00121     setup_verify_network();
00122 
00123     HttpsRequest *req = new HttpsRequest(network, SSL_CA_PEM, HTTP_GET, "https://os.mbed.com/media/uploads/mbed_official/hello.txt");
00124 
00125     HttpResponse* res = req->send();
00126     TEST_ASSERT(res);
00127     TEST_ASSERT_EQUAL(200, res->get_status_code());
00128     TEST_ASSERT(res->get_body_length() > 0);
00129     TEST_ASSERT_NOT_EQUAL(res->get_body_as_string().find("Hello world!"), string::npos);
00130 
00131     delete req;
00132 
00133     return CaseNext;
00134 }
00135 
00136 static control_t https_post(const size_t call_count) {
00137     setup_verify_network();
00138 
00139     HttpsRequest* req = new HttpsRequest(network, SSL_CA_PEM, HTTP_POST, "https://httpbin.org/post");
00140     req->set_header("Content-Type", "application/json");
00141 
00142     const char body[] = "{\"myhttpskey\":\"janjanjan\"}";
00143 
00144     HttpResponse* res = req->send(body, strlen(body));
00145     TEST_ASSERT(res);
00146     TEST_ASSERT_EQUAL(200, res->get_status_code());
00147 
00148     // verify that the Content-Type header is present, and set to application/json
00149     assert_header(res, "Content-Type", "application/json");
00150 
00151     // verify that both the key and value are present in the response
00152     TEST_ASSERT(res->get_body_length() > 0);
00153     TEST_ASSERT_NOT_EQUAL(res->get_body_as_string().find("myhttpskey"), string::npos);
00154     TEST_ASSERT_NOT_EQUAL(res->get_body_as_string().find("janjanjan"), string::npos);
00155 
00156     delete req;
00157 
00158     return CaseNext;
00159 }
00160 
00161 static control_t https_socket_reuse(const size_t call_count) {
00162     setup_verify_network();
00163 
00164     TLSSocket socket;
00165     nsapi_error_t open_result = socket.open(network);
00166     TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, open_result);
00167 
00168     nsapi_error_t ca_result = socket.set_root_ca_cert(SSL_CA_PEM);
00169     TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, ca_result);
00170 
00171     nsapi_error_t connect_result = socket.connect("httpbin.org", 443);
00172     TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, connect_result);
00173 
00174     {
00175         HttpsRequest *req = new HttpsRequest(&socket, HTTP_GET, "http://httpbin.org/status/404");
00176 
00177         HttpResponse* res = req->send();
00178         TEST_ASSERT(res);
00179         TEST_ASSERT_EQUAL(404, res->get_status_code());
00180 
00181         delete req;
00182     }
00183 
00184     {
00185         HttpsRequest *req = new HttpsRequest(&socket, HTTP_GET, "http://httpbin.org/status/403");
00186 
00187         HttpResponse* res = req->send();
00188         TEST_ASSERT(res);
00189         TEST_ASSERT_EQUAL(403, res->get_status_code());
00190 
00191         delete req;
00192     }
00193 
00194     return CaseNext;
00195 }
00196 
00197 // Spread the message out over 3 different chunks
00198 const char * chunks[] = {
00199     "{\"message\":",
00200     "\"this is an example",
00201     " of chunked encoding\"}"
00202 };
00203 
00204 int chunk_ix = 0;
00205 
00206 // Callback function, grab the next chunk and return it
00207 const void * get_chunk(uint32_t* out_size) {
00208     // If you don't have any data left, set out_size to 0 and return a null pointer
00209     if (chunk_ix == (sizeof(chunks) / sizeof(chunks[0]))) {
00210         *out_size = 0;
00211         return NULL;
00212     }
00213     const char *chunk = chunks[chunk_ix];
00214     *out_size = strlen(chunk);
00215     chunk_ix++;
00216 
00217     return chunk;
00218 }
00219 
00220 static control_t chunked_request(const size_t call_count) {
00221     setup_verify_network();
00222 
00223     HttpsRequest *req = new HttpsRequest(network, SSL_CA_PEM, HTTP_POST, "https://reqres.in/api/users");
00224     req->set_header("Content-Type", "application/json");
00225 
00226     HttpResponse* res = req->send(&get_chunk);
00227     TEST_ASSERT(res);
00228     TEST_ASSERT_EQUAL(201, res->get_status_code());
00229     TEST_ASSERT(res->get_body_length() > 0);
00230     TEST_ASSERT_NOT_EQUAL(res->get_body_as_string().find("message"), string::npos);
00231     TEST_ASSERT_NOT_EQUAL(res->get_body_as_string().find("this is an example of chunked encoding"), string::npos);
00232     TEST_ASSERT_NOT_EQUAL(res->get_body_as_string().find("createdAt"), string::npos);
00233 
00234     delete req;
00235 
00236     return CaseNext;
00237 }
00238 
00239 utest::v1::status_t greentea_setup(const size_t number_of_cases) {
00240     GREENTEA_SETUP(1*60, "default_auto");
00241     return greentea_test_setup_handler(number_of_cases);
00242 }
00243 
00244 Case cases[] = {
00245     Case("http get", http_get),
00246     Case("http post", http_post),
00247     Case("http socket reuse", http_socket_reuse),
00248     Case("https get", https_get),
00249     Case("https post", https_post),
00250     Case("https socket reuse", https_socket_reuse),
00251     Case("chunked request", chunked_request)
00252 };
00253 
00254 Specification specification(greentea_setup, cases);
00255 
00256 void blink_led() {
00257     static DigitalOut led(LED1);
00258     led = !led;
00259 }
00260 
00261 int main() {
00262     Ticker t;
00263     t.attach(blink_led, 0.5);
00264 
00265     return !Harness::run(specification);
00266 }