This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

HTTPS GET Request using nRF9160 DK

Hi,

I am following this example here, which sends an https HEAD request to google.com as a starting point for my overall goal, which is to send an https GET or POST request to our own server. This works and I can view the response in the terminal, but I am wondering how I would be able to modify this example for a GET or POST request to google.com, and then a GET or POST request to my own server?

I looked at the following example here, but this didn't seem to work correctly. There seem to be some fundamental differences between these two examples, as one is an nRF Connect SDK example and one is a Zephyr example.

I found a few other posts that mentioned this example here, but I am unable to find this example when I open a new nRF connect SDK project.

Any help/advice would be greatly appreciated. Thanks!

Parents
  • Hi kgarland789,


    I would like to get some more info about your application.
    Are you mixing HTTPS and HTTP, could you show what you actually are sending etc.

    Snippets of code and output logs would be helpful.

  • Hi Martin,

    Thank you for your response!

    Sorry for the confusion, but I am using HTTPS only. Right now I am just working on getting a 200 response for GET and POST requests to our internal server. The end goal is to be sending data from our devices in the field to our internal server, so right now I am just testing out the basic GET and POST requests to get a feel for the nRF9160 and the SDK. I will paste my code below.

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
    #include <string.h>
    #include <zephyr.h>
    #include <stdlib.h>
    #include <net/socket.h>
    #include <modem/bsdlib.h>
    #include <net/tls_credentials.h>
    #include <modem/lte_lc.h>
    #include <modem/at_cmd.h>
    #include <modem/at_notif.h>
    #include <modem/modem_key_mgmt.h>
    
    //#define HTTPS_PORT 443
    //#define HTTP_PATH "/api"
    //#define HTTP_HOST "https://fleet-test.staflsystems.com"
    //#define HTTP_HEAD "GET " HTTP_PATH " HTTP/1.1\r\nHost: " HTTP_HOST "\r\n\r\n"
    
    //#define HTTP_HEAD_LEN (sizeof(HTTP_HEAD) - 1)
    
    //#define HTTP_HDR_END "\r\n\r\n"
    //
    //#define RECV_BUF_SIZE 2048
    #define TLS_SEC_TAG 42
    
    //static const char send_buf[] = HTTP_HEAD;
    //static char recv_buf[RECV_BUF_SIZE];
    
    
    
    #define HTTP_HOST "fleet-test.staflsystems.com"
    #define HTTP_PORT 443
    #define RECV_BUF_SIZE 4096
    
    char recv_buf[RECV_BUF_SIZE + 1];
    
    /* Certificate for `google.com` */
    static const char cert[] = {
    	#include "../cert/GlobalSign-Root-CA-R2"
    };
    
    BUILD_ASSERT(sizeof(cert) < KB(4), "Certificate too large");
    
    
    /* Initialize AT communications */
    int at_comms_init(void)
    {
    	int err;
    
    	err = at_cmd_init();
    	if (err) {
    		printk("Failed to initialize AT commands, err %d\n", err);
    		return err;
    	}
    
    	err = at_notif_init();
    	if (err) {
    		printk("Failed to initialize AT notifications, err %d\n", err);
    		return err;
    	}
    
    	return 0;
    }
    
    /* Provision certificate to modem */
    int cert_provision(void)
    {
    	int err;
    	bool exists;
    	uint8_t unused;
    
    	err = modem_key_mgmt_exists(TLS_SEC_TAG,
    				    MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN,
    				    &exists, &unused);
    	if (err) {
    		printk("Failed to check for certificates err %d\n", err);
    		return err;
    	}
    
    	if (exists) {
    		/* For the sake of simplicity we delete what is provisioned
    		 * with our security tag and reprovision our certificate.
    		 */
    		err = modem_key_mgmt_delete(TLS_SEC_TAG,
    					    MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN);
    		if (err) {
    			printk("Failed to delete existing certificate, err %d\n",
    			       err);
    		}
    	}
    
    	printk("Provisioning certificate\n");
    
    	/*  Provision certificate to the modem */
    	err = modem_key_mgmt_write(TLS_SEC_TAG,
    				   MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN,
    				   cert, sizeof(cert) - 1);
    	if (err) {
    		printk("Failed to provision certificate, err %d\n", err);
    		return err;
    	}
    
    	return 0;
    }
    
    /* Setup TLS options on a given socket */
    int tls_setup(int fd)
    {
    	int err;
    	int verify;
    
    	/* Security tag that we have provisioned the certificate with */
    	const sec_tag_t tls_sec_tag[] = {
    		TLS_SEC_TAG,
    	};
    
    	/* Set up TLS peer verification */
    	enum {
    		NONE = 0,
    		OPTIONAL = 1,
    		REQUIRED = 2,
    	};
    
    	verify = REQUIRED;
    
    	err = setsockopt(fd, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(verify));
    	if (err) {
    		printk("Failed to setup peer verification, err %d\n", errno);
    		return err;
    	}
    
    	/* Associate the socket with the security tag
    	 * we have provisioned the certificate with.
    	 */
    	err = setsockopt(fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_sec_tag,
    			 sizeof(tls_sec_tag));
    	if (err) {
    		printk("Failed to setup TLS sec tag, err %d\n", errno);
    		return err;
    	}
    
    	return 0;
    }
    
    
    
    void app_http_start(void)
    {
    	struct sockaddr_in local_addr;
    	struct addrinfo *res;
    	struct addrinfo hints;
    
    	hints.ai_flags = 0;
    	hints.ai_family = AF_INET;
    	hints.ai_socktype = SOCK_STREAM;
    	hints.ai_protocol = 0;
    
    	local_addr.sin_family = AF_INET;
    	local_addr.sin_port = htons(HTTP_PORT);
    	local_addr.sin_addr.s_addr = 0;
    
    	printk("HTTP example\n\r");
    
    	int err = getaddrinfo(HTTP_HOST, NULL, &hints, &res);
    	if (err) {
    		printk("getaddrinfo errno %d\n", errno);
    		/* No clean up needed, just return */
    		return;
    	}
    
    	((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTP_PORT);
    
    	char send_buf[] = "GET /api HTTP/1.1\r\nHost: fleet-test.staflsystems.com\r\n\r\n";
    	int send_data_len = strlen(send_buf);
    
    	int client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);
    
    	enum {
    		NONE = 0,
    		OPTIONAL = 1,
    		REQUIRED = 2,
    	};
    
    	int verify = OPTIONAL;
    
    	err = setsockopt(client_fd, SOL_TLS, TLS_PEER_VERIFY, &verify,
    			 sizeof(verify));
    	if (err) {
    		printk("setsockopt err: %d\n", errno);
    	}
    
    	err = connect(client_fd, (struct sockaddr *)res->ai_addr,
    		      sizeof(struct sockaddr_in));
    	if (err > 0) {
    		printk("connect err: %d\n", errno);
    		goto clean_up;
    	}
    
    	int num_bytes = send(client_fd, send_buf, send_data_len, 0);
    	if (num_bytes < 0) {
    		printk("send errno: %d\n", errno);
    		goto clean_up;
    	}
    
    	int tot_num_bytes = 0;
    
    	do {
    		/* TODO: make a proper timeout *
    		 * Current solution will just hang 
    		 * until remote side closes connection */
    		num_bytes = recv(client_fd, recv_buf, RECV_BUF_SIZE, 0);
    		tot_num_bytes += num_bytes;
                    printk("total number of bytes: %d\n", tot_num_bytes);
                    printk("num bytes: %d\n", num_bytes);
    		if (num_bytes < 0) {
    			printk("\nrecv errno: %d\n", errno);
    			break;
    		}
    		printk("%s\n", recv_buf);
    	} while (num_bytes > 0);
    
    	printk("\n\rFinished. Closing socket");
    clean_up:
    	freeaddrinfo(res);
    	err = close(client_fd);
    }
    
    void main(void)
    {        
            int err;
    	printk("HTTPS client sample started\n\r");
    
    	err = bsdlib_init();
    	if (err) {
    		printk("Failed to initialize bsdlib!");
    		return;
    	}
    
    	/* Initialize AT comms in order to provision the certificate */
    	err = at_comms_init();
    	if (err) {
    		return;
    	}
    
    	/* Provision certificates before connecting to the LTE network */
    	err = cert_provision();
    	if (err) {
    		return;
    	}
    
    	printk("Waiting for network.. ");
    	err = lte_lc_init_and_connect();
    	if (err) {
    		printk("Failed to connect to the LTE network, err %d\n", err);
    		return;
    	}
    	printk("OK\n");
    	app_http_start();
    	while (1) {
    		k_cpu_idle();
    	}
    }
    
    
    

    This is my response that I view over the LTE Link Monitor. Everything seems to look fine, but I am not getting the "closing socket" message.

    HTTPS client sample started
    Provisioning certificate
    Waiting for network.. OK
    HTTP example
    total number of bytes: 363
    num bytes: 363
    HTTP/1.1 200 
    OK
    Date: Wed, 05 Aug 2020 16:01:37 GMT
    Server: Apache/2.4.38 (Ubuntu)
    X-Powered-By: Express
    Access-Control-Allow-Origin: *
    Content-Type: application/json; charset=utf-8
    Content-Length: 57
    ETag: W/"39-6NyqtBalyBpemqjJ7ON6PfdGFIc"
    Via: 1.1 fleet-test.staflsystems.com (Apache/2.4.38)
    {"status":"good","message":"Good work with get requests"}

    The good thing is that I am getting a response, but is the code hanging, or continuously running? I would also like to adapt this for an HTTPS POST request, and was wondering what example to follow.

    Thank you for your assistance!

Reply
  • Hi Martin,

    Thank you for your response!

    Sorry for the confusion, but I am using HTTPS only. Right now I am just working on getting a 200 response for GET and POST requests to our internal server. The end goal is to be sending data from our devices in the field to our internal server, so right now I am just testing out the basic GET and POST requests to get a feel for the nRF9160 and the SDK. I will paste my code below.

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
     */
    
    #include <string.h>
    #include <zephyr.h>
    #include <stdlib.h>
    #include <net/socket.h>
    #include <modem/bsdlib.h>
    #include <net/tls_credentials.h>
    #include <modem/lte_lc.h>
    #include <modem/at_cmd.h>
    #include <modem/at_notif.h>
    #include <modem/modem_key_mgmt.h>
    
    //#define HTTPS_PORT 443
    //#define HTTP_PATH "/api"
    //#define HTTP_HOST "https://fleet-test.staflsystems.com"
    //#define HTTP_HEAD "GET " HTTP_PATH " HTTP/1.1\r\nHost: " HTTP_HOST "\r\n\r\n"
    
    //#define HTTP_HEAD_LEN (sizeof(HTTP_HEAD) - 1)
    
    //#define HTTP_HDR_END "\r\n\r\n"
    //
    //#define RECV_BUF_SIZE 2048
    #define TLS_SEC_TAG 42
    
    //static const char send_buf[] = HTTP_HEAD;
    //static char recv_buf[RECV_BUF_SIZE];
    
    
    
    #define HTTP_HOST "fleet-test.staflsystems.com"
    #define HTTP_PORT 443
    #define RECV_BUF_SIZE 4096
    
    char recv_buf[RECV_BUF_SIZE + 1];
    
    /* Certificate for `google.com` */
    static const char cert[] = {
    	#include "../cert/GlobalSign-Root-CA-R2"
    };
    
    BUILD_ASSERT(sizeof(cert) < KB(4), "Certificate too large");
    
    
    /* Initialize AT communications */
    int at_comms_init(void)
    {
    	int err;
    
    	err = at_cmd_init();
    	if (err) {
    		printk("Failed to initialize AT commands, err %d\n", err);
    		return err;
    	}
    
    	err = at_notif_init();
    	if (err) {
    		printk("Failed to initialize AT notifications, err %d\n", err);
    		return err;
    	}
    
    	return 0;
    }
    
    /* Provision certificate to modem */
    int cert_provision(void)
    {
    	int err;
    	bool exists;
    	uint8_t unused;
    
    	err = modem_key_mgmt_exists(TLS_SEC_TAG,
    				    MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN,
    				    &exists, &unused);
    	if (err) {
    		printk("Failed to check for certificates err %d\n", err);
    		return err;
    	}
    
    	if (exists) {
    		/* For the sake of simplicity we delete what is provisioned
    		 * with our security tag and reprovision our certificate.
    		 */
    		err = modem_key_mgmt_delete(TLS_SEC_TAG,
    					    MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN);
    		if (err) {
    			printk("Failed to delete existing certificate, err %d\n",
    			       err);
    		}
    	}
    
    	printk("Provisioning certificate\n");
    
    	/*  Provision certificate to the modem */
    	err = modem_key_mgmt_write(TLS_SEC_TAG,
    				   MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN,
    				   cert, sizeof(cert) - 1);
    	if (err) {
    		printk("Failed to provision certificate, err %d\n", err);
    		return err;
    	}
    
    	return 0;
    }
    
    /* Setup TLS options on a given socket */
    int tls_setup(int fd)
    {
    	int err;
    	int verify;
    
    	/* Security tag that we have provisioned the certificate with */
    	const sec_tag_t tls_sec_tag[] = {
    		TLS_SEC_TAG,
    	};
    
    	/* Set up TLS peer verification */
    	enum {
    		NONE = 0,
    		OPTIONAL = 1,
    		REQUIRED = 2,
    	};
    
    	verify = REQUIRED;
    
    	err = setsockopt(fd, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(verify));
    	if (err) {
    		printk("Failed to setup peer verification, err %d\n", errno);
    		return err;
    	}
    
    	/* Associate the socket with the security tag
    	 * we have provisioned the certificate with.
    	 */
    	err = setsockopt(fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_sec_tag,
    			 sizeof(tls_sec_tag));
    	if (err) {
    		printk("Failed to setup TLS sec tag, err %d\n", errno);
    		return err;
    	}
    
    	return 0;
    }
    
    
    
    void app_http_start(void)
    {
    	struct sockaddr_in local_addr;
    	struct addrinfo *res;
    	struct addrinfo hints;
    
    	hints.ai_flags = 0;
    	hints.ai_family = AF_INET;
    	hints.ai_socktype = SOCK_STREAM;
    	hints.ai_protocol = 0;
    
    	local_addr.sin_family = AF_INET;
    	local_addr.sin_port = htons(HTTP_PORT);
    	local_addr.sin_addr.s_addr = 0;
    
    	printk("HTTP example\n\r");
    
    	int err = getaddrinfo(HTTP_HOST, NULL, &hints, &res);
    	if (err) {
    		printk("getaddrinfo errno %d\n", errno);
    		/* No clean up needed, just return */
    		return;
    	}
    
    	((struct sockaddr_in *)res->ai_addr)->sin_port = htons(HTTP_PORT);
    
    	char send_buf[] = "GET /api HTTP/1.1\r\nHost: fleet-test.staflsystems.com\r\n\r\n";
    	int send_data_len = strlen(send_buf);
    
    	int client_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);
    
    	enum {
    		NONE = 0,
    		OPTIONAL = 1,
    		REQUIRED = 2,
    	};
    
    	int verify = OPTIONAL;
    
    	err = setsockopt(client_fd, SOL_TLS, TLS_PEER_VERIFY, &verify,
    			 sizeof(verify));
    	if (err) {
    		printk("setsockopt err: %d\n", errno);
    	}
    
    	err = connect(client_fd, (struct sockaddr *)res->ai_addr,
    		      sizeof(struct sockaddr_in));
    	if (err > 0) {
    		printk("connect err: %d\n", errno);
    		goto clean_up;
    	}
    
    	int num_bytes = send(client_fd, send_buf, send_data_len, 0);
    	if (num_bytes < 0) {
    		printk("send errno: %d\n", errno);
    		goto clean_up;
    	}
    
    	int tot_num_bytes = 0;
    
    	do {
    		/* TODO: make a proper timeout *
    		 * Current solution will just hang 
    		 * until remote side closes connection */
    		num_bytes = recv(client_fd, recv_buf, RECV_BUF_SIZE, 0);
    		tot_num_bytes += num_bytes;
                    printk("total number of bytes: %d\n", tot_num_bytes);
                    printk("num bytes: %d\n", num_bytes);
    		if (num_bytes < 0) {
    			printk("\nrecv errno: %d\n", errno);
    			break;
    		}
    		printk("%s\n", recv_buf);
    	} while (num_bytes > 0);
    
    	printk("\n\rFinished. Closing socket");
    clean_up:
    	freeaddrinfo(res);
    	err = close(client_fd);
    }
    
    void main(void)
    {        
            int err;
    	printk("HTTPS client sample started\n\r");
    
    	err = bsdlib_init();
    	if (err) {
    		printk("Failed to initialize bsdlib!");
    		return;
    	}
    
    	/* Initialize AT comms in order to provision the certificate */
    	err = at_comms_init();
    	if (err) {
    		return;
    	}
    
    	/* Provision certificates before connecting to the LTE network */
    	err = cert_provision();
    	if (err) {
    		return;
    	}
    
    	printk("Waiting for network.. ");
    	err = lte_lc_init_and_connect();
    	if (err) {
    		printk("Failed to connect to the LTE network, err %d\n", err);
    		return;
    	}
    	printk("OK\n");
    	app_http_start();
    	while (1) {
    		k_cpu_idle();
    	}
    }
    
    
    

    This is my response that I view over the LTE Link Monitor. Everything seems to look fine, but I am not getting the "closing socket" message.

    HTTPS client sample started
    Provisioning certificate
    Waiting for network.. OK
    HTTP example
    total number of bytes: 363
    num bytes: 363
    HTTP/1.1 200 
    OK
    Date: Wed, 05 Aug 2020 16:01:37 GMT
    Server: Apache/2.4.38 (Ubuntu)
    X-Powered-By: Express
    Access-Control-Allow-Origin: *
    Content-Type: application/json; charset=utf-8
    Content-Length: 57
    ETag: W/"39-6NyqtBalyBpemqjJ7ON6PfdGFIc"
    Via: 1.1 fleet-test.staflsystems.com (Apache/2.4.38)
    {"status":"good","message":"Good work with get requests"}

    The good thing is that I am getting a response, but is the code hanging, or continuously running? I would also like to adapt this for an HTTPS POST request, and was wondering what example to follow.

    Thank you for your assistance!

Children
Related