Search code examples
httpsslcurlsmtpwxwidgets

Sending feedback data via HTTPS POST from wxWidgets application


I have a wxWidgets application and would like to add a way for users to submit feedback in a simple (implementation and usage), reliable, cross-platform and secure way. Using HTTP POST over SSL seems to fit those requirements best (although I'll consider answers that suggest other approaches). However, support for HTTPS in wxWidgets seems limited.

Here are some of the options I've considered and the problems with them:

  • wxSMTP: no SSL/TLS support that I've found. Relies on user having a correct mail configuration (sendmail, MAPI).
  • wxHTTP: everything but SSL/HTTPS support.
  • wxSSL: everything if it wasn't incomplete and long dead.
  • wxCURL: everything but complicated to build/incorporate (in fact currently release fails to build).
  • libcurl: just link with and call into libcurl directly. This is the solution I've settled on (and I have a working prototype) but it feels very non-wx and while libcurl is cross-platform, Windows is definitely not its native platform so it adds significant dependency and build complexity to the project.

Solution

  • I've decided to go with libCURL linked to openssl. Both of the packages are able availabe on most Linux system and can be fairly easily built on Windows and OS X.

    Here is example C code that sends feedback:

    #include <stdio.h>
    #include <string.h>
    
    #include <curl/curl.h>
    #include <curl/types.h>
    #include <curl/easy.h>
    
    int main(int argc, char *argv[])
    {
      CURL *curl;
      CURLcode res;
    
      struct curl_httppost *formpost=NULL;
      struct curl_httppost *lastptr=NULL;
      struct curl_slist *headerlist=NULL;
      static const char buf[] = "Expect:";
    
      curl_global_init(CURL_GLOBAL_ALL);
    
      /* Fill in the name field */
      curl_formadd(&formpost,
                   &lastptr,
                   CURLFORM_COPYNAME, "name",
                   CURLFORM_COPYCONTENTS, "John Doe",
                   CURLFORM_END);
    
      /* Fill in the comments field */
      curl_formadd(&formpost,
                   &lastptr,
                   CURLFORM_COPYNAME, "comments",
                   CURLFORM_COPYCONTENTS, "using HTTPS POST\nline 2\nline 3",
                   CURLFORM_END);
    
      curl = curl_easy_init();
      /* initalize custom header list (stating that Expect: 100-continue is not
         wanted */
      headerlist = curl_slist_append(headerlist, buf);
      if(curl) {
        /* what URL that receives this POST */
        curl_easy_setopt(curl, CURLOPT_URL, 
            "https://some_host.com/path/feedback.php");
    
        // Uncomment to disable certificate checks
        //curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
        //curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
    
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
        curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
        res = curl_easy_perform(curl);
    
        printf("Curl result: %d\n", res);
    
        /* always cleanup */
        curl_easy_cleanup(curl);
    
        /* then cleanup the formpost chain */
        curl_formfree(formpost);
        /* free slist */
        curl_slist_free_all (headerlist);
      }
      return 0;
    }
    

    That can be compiled on Linux like so:

    gcc post.c -lcurl -o post
    

    Here is example PHP code that accepts that post:

    <?php
        $recipient = "john@some_host.com";
        if (empty($_POST)) {
            // We only accpet POSTs
            header('HTTP/1.0 403 Forbidden');
            exit;
        } else {
            // Handle a POST
            $message .= "Submitted at ".date("F j, Y, g:i a")."\n\n";
            $message .= "Name:\n";
            $message .= $_POST['name']."\n\n";
            $message .= "-------------------------------------------\n\n";
            $message .= "Comments:\n\n";
            $message .= $_POST['comments']."\n\n";
            // Send message to email address
            $sent = mail($recipient, "Feedback", 
                $message, "From: Feedback <noreply@some_host.com>\r\n");
    
            if ($sent) {
    ?>
                <html>
                <body>
                    Got POST and sent email:
                    <pre><? echo $message; ?></pre>
                </body>
                </html>
    <?php
            } else {
                // Return an error
                header('HTTP/1.0 500 Internal Server Error', true, 500);
                exit;
            }
        }
    ?>