The goal of this task is to demonstrate HTTPS requests with authentication. Implementations of this task should not use client certificates for this: that is the subject of another task.

Task
HTTPS/Authenticated
You are encouraged to solve this task according to the task description, using any language you may know.

Arturo

user: "admin"
pass: "admin"

inspect request.headers:#[
    Authorization: "Basic " ++ encode user ++ ":" ++ pass
] "https://httpbin.org/basic-auth/admin/admin" ø
Output:
[ :dictionary
	version  :	1.1 :string
	body     :	{
  "authenticated": true, 
  "user": "admin"
}
 :string
	headers  :	[ :dictionary
		server                            :		gunicorn/19.9.0 :string
		content-length                    :		48 :integer
		access-control-allow-credentials  :		true :logical
		content-type                      :		application/json :string
		date                              :		[ :date
			hour        :			15 :integer
			minute      :			14 :integer
			second      :			57 :integer
			nanosecond  :			0 :integer
			day         :			20 :integer
			Day         :			Tuesday :string
			days        :			353 :integer
			month       :			12 :integer
			Month       :			December :string
			year        :			2022 :integer
			utc         :			-3600 :integer
		]
		access-control-allow-origin       :		* :string
		connection                        :		keep-alive :string
	]
	status   :	200 :integer
]

AutoHotkey

Library: iweb
Library: COM
iWeb_Init()
pwb := iWeb_newGui(0, 0, 1000, 800)
iWeb_nav(pwb, "http://www.facebook.com/login.php?ref=pf")
iWeb_Term()
iWeb_complete(pwb)
inputbox, email, email
inputbox, pass, password
iWeb_setDomObj(pwb,"Email",email)
iWeb_setDomObj(pwb,"pass",pass)
iWeb_clickDomObj(pwb, "login")
return

#Include iweb.ahk
#Include COM.ahk
#Include COMinvokeDeep.ahk

BaCon

OPTION TLS TRUE

website$ = "website.com"
username$ = "nobody"
password$ = "ignore"

OPEN website$ & ":443" FOR NETWORK AS conn
SEND "GET / HTTP/1.1\r\nHost: " & website$ & "\r\nAuthorization: Basic " & B64ENC$(username$ & ":" & password$) & "\r\n\r\n" TO conn

WHILE WAIT(conn, 2000)
    RECEIVE data$ FROM conn
    total$ = total$ & data$
    IF INSTR(data$, "</html>") THEN BREAK
WEND
CLOSE NETWORK conn

PRINT total$

C

Library: libcurl
#include <stdio.h>
#include <stdlib.h>
#include "curl/curl.h"

int
main(void)
{
        CURL *curl;
        char buffer[CURL_ERROR_SIZE];

        if ((curl = curl_easy_init()) != NULL) {
                curl_easy_setopt(curl, CURLOPT_URL, "https://user:password@secure.example.com/");
                curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
                curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, buffer);
                if (curl_easy_perform(curl) != CURLE_OK) {
                        fprintf(stderr, "%s\n", buffer);
                        return EXIT_FAILURE;
                }
                curl_easy_cleanup(curl);
        }
        return EXIT_SUCCESS;
}

C#

Works with: C sharp version 3.0
using System;
using System.Net;

class Program
{
    static void Main(string[] args)
    {
        var client = new WebClient();

        // credentials of current user:
        client.Credentials = CredentialCache.DefaultCredentials;
        // or specify credentials manually:
        client.Credentials = new NetworkCredential("User", "Password");

        var data = client.DownloadString("https://example.com");

        Console.WriteLine(data);
    }
}

Clojure

Library: clj-http
(clj-http.client/get "https://somedomain.com" 
                     {:basic-auth ["user" "pass"]})

Delphi

program ShowHTTPSAuthenticated;

{$APPTYPE CONSOLE}

uses IdHttp, IdSSLOpenSSL;

var
  s: string;
  lHTTP: TIdHTTP;
  lIOHandler: TIdSSLIOHandlerSocketOpenSSL;
begin
  ReportMemoryLeaksOnShutdown := True;
  lHTTP := TIdHTTP.Create(nil);
  lIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  try
    lHTTP.Request.Username := 'USERNAME';
    lHTTP.Request.Password := 'PASSWD';
    lHTTP.IOHandler := lIOHandler;
    lHTTP.HandleRedirects := True;
    s := lHTTP.Get('https://SomeSecureSite.net/');
    Writeln(s);
  finally
    lHTTP.Free;
    lIOHandler.Free;
  end;
end.

FreeBASIC

Library: wininet
#include once "windows.bi"
#include once "win/wininet.bi"

' Create InternetOpen and InternetConnect objects
Dim As HINTERNET hInternet, hConnect
hInternet = InternetOpen("FreeBASIC", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0)
hConnect = InternetConnect(hInternet, "www.abc.com", INTERNET_DEFAULT_HTTP_PORT, "<username>", "<password>", INTERNET_SERVICE_HTTP, 0, 0)

' Open request
Dim As HINTERNET hRequest
hRequest = HttpOpenRequest(hConnect, "GET", "/xyz/index.html", NULL, NULL, NULL, INTERNET_FLAG_SECURE, 0)

#If USE_PROXY
    ' Set proxy
    Dim As INTERNET_PROXY_INFO proxyInfo
    proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY
    proxyInfo.lpszProxy = "10.167.1.1:80"
    proxyInfo.lpszProxyBypass = NULL
    InternetSetOption(hRequest, INTERNET_OPTION_PROXY, @proxyInfo, Sizeof(proxyInfo))
#endif

' Set timeouts
Dim As DWORD dwTimeout = 1000
InternetSetOption(hRequest, INTERNET_OPTION_CONNECT_TIMEOUT, @dwTimeout, Sizeof(dwTimeout))
InternetSetOption(hRequest, INTERNET_OPTION_RECEIVE_TIMEOUT, @dwTimeout, Sizeof(dwTimeout))
InternetSetOption(hRequest, INTERNET_OPTION_SEND_TIMEOUT, @dwTimeout, Sizeof(dwTimeout))

' Send request
HttpSendRequest(hRequest, NULL, 0, NULL, 0)

' Print response
Dim As Byte buffer(4096)
Dim As DWORD dwRead
While InternetReadFile(hRequest, @buffer(0), Sizeof(buffer), @dwRead) And dwRead > 0
    For i As Integer = 0 To dwRead-1
        Print Chr(buffer(i));
    Next
Wend

' Clean up
InternetCloseHandle(hRequest)
InternetCloseHandle(hConnect)
InternetCloseHandle(hInternet)

Sleep

Go

The task solution is really the client program, but to test it I wrote a server and created a custom certificate. I won't describe the certificate, but this is the server:

package main

import (
    "encoding/base64"
    "io"
    "log"
    "net/http"
    "strings"
)

const userPass = "rosetta:code"
const unauth = http.StatusUnauthorized

func hw(w http.ResponseWriter, req *http.Request) {
    auth := req.Header.Get("Authorization")
    if !strings.HasPrefix(auth, "Basic ") {
        log.Print("Invalid authorization:", auth)
        http.Error(w, http.StatusText(unauth), unauth)
        return
    }
    up, err := base64.StdEncoding.DecodeString(auth[6:])
    if err != nil {
        log.Print("authorization decode error:", err)
        http.Error(w, http.StatusText(unauth), unauth)
        return
    }
    if string(up) != userPass {
        log.Print("invalid username:password:", string(up))
        http.Error(w, http.StatusText(unauth), unauth)
        return
    }
    io.WriteString(w, "Goodbye, World!")
}

func main() {
    http.HandleFunc("/", hw)
    log.Fatal(http.ListenAndServeTLS(":8080", "cert.pem", "key.pem", nil))
}

It is a "Hello world" server, but over TLS and with basic authentication required on the Get. Errors are logged to aid client debugging.

The client:

package main

import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

const (
    userid   = "rosetta"
    password = "code"
)

func main() {
    // Use custom certificate for testing.  Not exactly required by task.
    b, err := ioutil.ReadFile("cert.pem")
    if err != nil {
        log.Fatal(err)
    }
    pool := x509.NewCertPool()
    if ok := pool.AppendCertsFromPEM(b); !ok {
        log.Fatal("Failed to append cert")
    }
    tc := &tls.Config{RootCAs: pool}
    tr := &http.Transport{TLSClientConfig: tc}
    client := &http.Client{Transport: tr}
    req, err := http.NewRequest("GET", "https://127.0.0.1:8080", nil)
    if err != nil {
        log.Fatal(err)
    }

    // This one line implements the authentication required for the task.
    req.SetBasicAuth(userid, password)

    // Make request and show output.
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    b, err = ioutil.ReadAll(resp.Body)
    resp.Body.Close()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(b))
}

Haskell

Example uses the req and aeson packages:

{-# LANGUAGE OverloadedStrings #-}

module Main (main) where

import           Data.Aeson (Value)
import           Data.Default.Class (def)
import           Network.HTTP.Req
                    ( (/:)
                    , GET(..)
                    , NoReqBody(..)
                    , basicAuth
                    , https
                    , jsonResponse
                    , req
                    , responseBody
                    , runReq
                    )

main :: IO ()
main = do
    response <- runReq def $ req
            GET
            (https "httpbin.org" /: "basic-auth" /: "someuser" /: "somepassword")
            NoReqBody
            jsonResponse
            (basicAuth "someuser" "somepassword")
    print (responseBody response :: Value)

Java

import java.io.IOException;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;

public final class HTTPSAuthenticated {

	public static void main(String[] aArgs) throws IOException, InterruptedException, URISyntaxException {
		HttpClient client = HttpClient.newBuilder()
			.authenticator( new MyAuthenticator() )
			.build();

		HttpRequest request = HttpRequest.newBuilder()
			.GET()
			.uri( new URI("https://postman-echo.com/basic-auth") ) // This website requires authentication
			.build();

		HttpResponse<String> response = client.send(request, BodyHandlers.ofString());

		System.out.println("Status: " +  response.statusCode());
	}

}

final class MyAuthenticator extends Authenticator {
	
	@Override
	protected PasswordAuthentication getPasswordAuthentication() {
		String username = "kingkong";
		String password = "test1234";
		return new PasswordAuthentication(username, password.toCharArray());
	}
	
}
Output:
Status: 200

Julia

An example using HTTP (see the source for HTTP.jl for the code below ) to access and play a song:

using HTTP, HTTP.IOExtras, JSON, MusicProcessing
HTTP.open("POST", "http://music.com/play") do io
    write(io, JSON.json([
        "auth" => "12345XXXX",
        "song_id" => 7,
    ]))
    r = startread(io)
    @show r.status
    while !eof(io)
        bytes = readavailable(io)
        play(bytes)
    end
end

Kotlin

// version 1.2.0

import java.net.Authenticator
import java.net.PasswordAuthentication
import javax.net.ssl.HttpsURLConnection
import java.net.URL
import java.io.InputStreamReader
import java.io.BufferedReader

object PasswordAuthenticator : Authenticator() {
    override fun getPasswordAuthentication() =
        PasswordAuthentication ("username", "password".toCharArray())
}

fun main(args: Array<String>) {
    val url = URL("https://somehost.com")
    val con = url.openConnection() as HttpsURLConnection
    Authenticator.setDefault(PasswordAuthenticator)
    con.allowUserInteraction = true
    con.connect()
    val isr = InputStreamReader(con.inputStream)
    val br = BufferedReader(isr)
    while (true) {
        val line = br.readLine()
        if (line == null) break
        println(line)
    }
}

Lasso

local(username = 'hello',password = 'world')
local(x = curl('https://sourceforge.net'))
#x->set(CURLOPT_USERPWD, #username + ':' + #password)
local(y = #x->result)
#y->asString

LiveCode

HTTP Basic Auth as part of url

command getAuthWebResource
    libURLFollowHttpRedirects true
    libURLSetSSLVerification true
    put URL "https://user:passwd@example.basicauth.com/" into response
    put response
end getAuthWebResource

You can also set the headers for the basic auth requests

command getAuthWebResource
    libURLFollowHttpRedirects true
    libURLSetSSLVerification true
    set the httpHeaders to "Authorization: Basic " && base64Encode("user:passwd")
    put URL "https://example.basicauth.com" into response
    put response
end getAuthWebResource

Lua

Works with: Lua version 5.1 - 5.3
Library: lua-requests
local requests = require('requests')
local auth = requests.HTTPBasicAuth('admin', 'admin')
local resp, e = requests.get({
  url = 'https://httpbin.org/basic-auth/admin/admin',
  auth = auth
})
io.write(string.format('Status: %d', resp.status_code))
Output:
Status: 200

Mathematica / Wolfram Language

a = RunThrough["curl -u JohnDoe:Password https://www.example.com", 1]
For[ i=0, i < Length[a] , i++, SomeFunction[a]]

Nim

Library: OpenSSL

Compile with command nim c -d:ssl https_authenticated.nim.

import httpclient, base64

const
  User = "admin"
  Password = "admin"

let headers = newHttpHeaders({"Authorization": "Basic " & base64.encode(User & ":" & Password)})
let client = newHttpClient(headers = headers)
echo client.getContent("https://httpbin.org/basic-auth/admin/admin")

PascalABC.NET

##
uses System.Net;

var wc := new WebClient();
wc.Credentials := new NetworkCredential('admin', 'admin');
var content := wc.DownloadString('https://httpbin.org/basic-auth/admin/admin');
content.Println

Perl

Library: LWP
use LWP::UserAgent qw();
my $ua = LWP::UserAgent->new;
my $netloc = 'http://www.buddhism-dict.net/cgi-bin/xpr-dealt.pl:80';
$ua->credentials(
   $netloc,
   'CJK-E and Buddhist Dictionaries', # basic realm
   'guest',  # user
   '',       # empty pw
);
my $response = $ua->get($netloc);

use WWW::Mechanize qw();
my $mech = WWW::Mechanize->new;
$mech->get('https://login.yahoo.com/');
$mech->submit_form(with_fields => {
    login         => 'XXXXXX',
    passwd        => 'YYYYYY',
    '.persistent' => 'y',  # tick checkbox
});

Phix

Library: Phix/libcurl

Exactly the same as the HTTP#Phix task. You can of course use curl_easy_setopt(curl,CURLOPT_USERPWD,"user:password") rather than embed that in the url.

without js
include builtins\libcurl.e
curl_global_init()
atom curl = curl_easy_init()
curl_easy_setopt(curl, CURLOPT_URL, "https://user:password@example.com/")
object res = curl_easy_perform_ex(curl)
curl_easy_cleanup(curl)
curl_global_cleanup()
 
puts(1,res)

PicoLisp

(let (User "Bill"  Pass "T0p5ecRet"  Url "https://www.example.com")
   (in (list 'curl "-u" (pack User ': Pass) Url)
      (while (line)
         (doSomeProcessingWithLine @) ) ) )

PowerShell

Translation of: C#
$client = [Net.WebClient]::new()
# credentials of current user:
$client.Credentials = [Net.CredentialCache]::DefaultCredentials
# or specify credentials manually:
# $client.Credentials = [System.Net.NetworkCredential]::new("User", "Password")
$data = $client.DownloadString("https://example.com")
Write-Host $data

Python

Works with: Python version 2.4 and 2.6

Note: You should install mechanize to run code below. Visit: http://wwwsearch.sourceforge.net/mechanize/

#!/usr/bin/python
# -*- coding: utf-8 -*-

from mechanize import Browser

USER_AGENT = "Mozilla/5.0 (X11; U; Linux i686; tr-TR; rv:1.8.1.9) Gecko/20071102 Pardus/2007 Firefox/2.0.0.9"

br = Browser()
br.addheaders = [("User-agent", USER_AGENT)]

# remove comment if you get debug output
# br.set_debug_redirects(True)
# br.set_debug_responses(True)
# br.set_debug_http(True)

br.open("https://www.facebook.com")

br.select_form("loginform")
br['email'] = "xxxxxxx@xxxxx.com"
br['pass'] = "xxxxxxxxx"
br['persistent'] = ["1"]

response = br.submit()
print response.read()
Library: Requests
Works with: Python version 2.7, 3.4–3.7
import requests

username = "user"
password = "pass"
url = "https://www.example.com"

response = requests.get(url, auth=(username, password)

print(response.text)

Racket

#lang racket

(require net/url net/url-connect openssl)

(module+ main
  (parameterize ([current-https-protocol (ssl-make-client-context)])
    (ssl-set-verify! (current-https-protocol) #t)

    ;; When this is #f, we correctly get an exception:
    ;; error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
    (when #t
      (ssl-load-verify-source! (current-https-protocol)
                               '(directory
                                 ;; This location works on Debian 6;
                                 ;; adjust as needed for your platform.
                                 "/etc/ssl/certs"
                                 )))

    (for ([l (in-port read-line (get-pure-port (string->url "https://www.google.com/")))])
      (displayln  l))))

Raku

(formerly Perl 6)

Works with: Rakudo version 2017.09

Used here to connect to my local wireless router to a page that is password protected. Obviously not going to be generally publicly accessible but should be easily adaptable to other sites / devices.

use HTTP::UserAgent;

my $username = 'username'; # my username
my $password = 'password'; # my password
my $address  = 'http://192.168.1.1/Status_Router.asp'; # my local wireless router

my $ua = HTTP::UserAgent.new;
$ua.auth( $username, $password );
my $response = $ua.get: $address;
say $response.is-success ?? $response.content !! $response.status-line;

Ruby

require 'uri'
require 'net/http'

uri = URI.parse('https://www.example.com')
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  request = Net::HTTP::Get.new uri
  request.basic_auth('username', 'password')
  http.request request
end

Run BASIC

html "
<CENTER><TABLE CELLPADDING=0 CELLSPACING=0 border=1 bgcolor=wheat>
<TR><TD colspan=2 bgcolor=tan align=center>LOGIN</TD></TR>
<TR><TD align=right>UserName</TD><TD>" 
 TEXTBOX #userName, "" 
html "</TR></TD><TR><TD align=right>Password:</TD><TD>"
PasswordBox  #passWord, "" 

html "</TD></TR><TD align=center colspan=2>"
button #si, "Signin", [doSignin]
html "   "
button #ex, "Exit", [exit]
html "</TD></TR></TABLE>"
WAIT

[doSignin]
loginUserName$    = trim$(#userName contents$())
loginPassWord$    = trim$(#passWord contents$())
if (loginUserName$ = "admin" and loginPassWord$ = "admin" then
   print "Login ok"
  else
   print "invalid User or Pass"
   cls
   goto [loop]
end if

print Platform$    ' OS where Run BASIC is being hosted
print UserInfo$    ' Information about the user's web browser
print UserAddress$ ' IP address of the user

[exit]
end

 

Rust

extern crate reqwest;

use reqwest::blocking::Client;
use reqwest::header::CONNECTION;

fn main() {
    let client = Client::new();

    // reqwest uses strongly-typed structs for creating headers
    let res = client
        .get("https://www.example.com")
        .basic_auth("user", Some("password"))
        .header(CONNECTION, "close")
        .send()
        .unwrap();

    let body = res.text().unwrap();

    println!("{}", body);
}
Output:


Scala

import java.net.{Authenticator, PasswordAuthentication, URL}

import javax.net.ssl.HttpsURLConnection

import scala.io.BufferedSource


object Authenticated extends App {

  val con: HttpsURLConnection =
    new URL("https://somehost.com").openConnection().asInstanceOf[HttpsURLConnection]

  object PasswordAuthenticator extends Authenticator {
    override def getPasswordAuthentication = 
      new PasswordAuthentication("username", "password".toCharArray)
  }

  Authenticator.setDefault(PasswordAuthenticator)
  con.setAllowUserInteraction(true)
  con.connect()

  new BufferedSource(con.getInputStream).getLines.foreach(println(_))

}

Sidef

require('WWW::Mechanize')

var mech = %s'WWW::Mechanize'.new(
    cookie_jar => Hash.new,
    agent => 'Mozilla/5.0',
)

mech.get('https://login.yahoo.com/')
mech.submit_form(
    form_id => 'mbr-login-form',   # form id
    fields => Hash.new(
        'login'  => 'XXXXXX',
        'passwd' => 'YYYYYY',
))

Tcl

Works with: Tcl version 8.6

for the binary encode subcommand, otherwise uses

Library: Tcllib (Package: base64)

Uses the Tls package.

package require http
package require tls
http::register https 443 ::tls::socket

# Generate the authentication
set user theUser
set pass thePassword
dict set auth Authenticate "Basic [binary encode base64 ${user}:${pass}]"

# Make a secure authenticated connection
set token [http::geturl https://secure.example.com/ -headers $auth]

# Now as for conventional use of the “http” package
set data [http::data $token]
http::cleanup $token

Visual Basic

Works with: Visual Basic version 5
Works with: Visual Basic version 6
Works with: VBA version Access 97
Works with: VBA version 6.5
Works with: VBA version 7.1
Sub Main()
'  in the "references" dialog of the IDE, check
'  "Microsoft WinHTTP Services, version 5.1" (winhttp.dll)
Dim HttpReq As WinHttp.WinHttpRequest
Const WINHTTP_FLAG_SECURE_PROTOCOL_TLS1     As Long = &H80&
Const WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1   As Long = &H200&
Const WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2   As Long = &H800&
Const HTTPREQUEST_PROXYSETTING_PROXY        As Long = 2
#Const USE_PROXY = 1
  Set HttpReq = New WinHttp.WinHttpRequest
  HttpReq.Open "GET", "https://www.abc.com/xyz/index.html"
  HttpReq.Option(WinHttpRequestOption_SecureProtocols) = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 Or _
                                                         WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 Or _
                                                         WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2
  HttpReq.SetCredentials "<username>", "<password>", 0&
#If USE_PROXY Then
  HttpReq.SetProxy HTTPREQUEST_PROXYSETTING_PROXY, "10.167.1.1:80"
#End If
  HttpReq.SetTimeouts 1000, 1000, 1000, 1000
  HttpReq.Send
  Debug.Print HttpReq.ResponseText
End Sub

Wren

Translation of: C
Library: libcurl

An embedded program so we can ask the C host to communicate with libcurl for us.

/* HTTPS_Authenticated.wren */

var CURLOPT_URL = 10002
var CURLOPT_FOLLOWLOCATION = 52
var CURLOPT_ERRORBUFFER = 10010

foreign class Curl {
    construct easyInit() {}

    foreign easySetOpt(opt, param)

    foreign easyPerform()

    foreign easyCleanup()
}

var curl = Curl.easyInit()
if (curl == 0) {
    System.print("Error initializing cURL.")
    return
}
curl.easySetOpt(CURLOPT_URL, "https://user:password@secure.example.com/")
curl.easySetOpt(CURLOPT_FOLLOWLOCATION, 1)
curl.easySetOpt(CURLOPT_ERRORBUFFER, 0) // buffer to be supplied by C

var status = curl.easyPerform()
if (status != 0) {
    System.print("Failed to perform task.")
    return
}
curl.easyCleanup()


We now embed this in the following C program, compile and run it.

/* gcc HTTPS_Authenticated.c -o HTTPS_Authenticated -lcurl -lwren -lm  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "wren.h"

/* C <=> Wren interface functions */

void C_curlAllocate(WrenVM* vm) {
    CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*));
    *pcurl = curl_easy_init();
}

void C_easyPerform(WrenVM* vm) {
    CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
    CURLcode cc = curl_easy_perform(curl);
    wrenSetSlotDouble(vm, 0, (double)cc);
}

void C_easyCleanup(WrenVM* vm) {
    CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
    curl_easy_cleanup(curl);
}

void C_easySetOpt(WrenVM* vm) {
    CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
    CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1);
    if (opt < 10000) {
        long lparam = (long)wrenGetSlotDouble(vm, 2);
        curl_easy_setopt(curl, opt, lparam);
    } else {
        if (opt == CURLOPT_URL) {
            const char *url = wrenGetSlotString(vm, 2);
            curl_easy_setopt(curl, opt, url);
        } else if (opt == CURLOPT_ERRORBUFFER) {
            char buffer[CURL_ERROR_SIZE];
            curl_easy_setopt(curl, opt, buffer);
        }
    }
}

WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
    WrenForeignClassMethods methods;
    methods.allocate = NULL;
    methods.finalize = NULL;
    if (strcmp(module, "main") == 0) {
        if (strcmp(className, "Curl") == 0) {
            methods.allocate = C_curlAllocate;
        }
    }
    return methods;
}

WrenForeignMethodFn bindForeignMethod(
    WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature) {
    if (strcmp(module, "main") == 0) {
        if (strcmp(className, "Curl") == 0) {
            if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt;
            if (!isStatic && strcmp(signature, "easyPerform()") == 0)   return C_easyPerform;
            if (!isStatic && strcmp(signature, "easyCleanup()") == 0)   return C_easyCleanup;
        }
    }
    return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
    printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
    switch (errorType) {
        case WREN_ERROR_COMPILE:
            printf("[%s line %d] [Error] %s\n", module, line, msg);
            break;
        case WREN_ERROR_STACK_TRACE:
            printf("[%s line %d] in %s\n", module, line, msg);
            break;
        case WREN_ERROR_RUNTIME:
            printf("[Runtime Error] %s\n", msg);
            break;
    }
}

char *readFile(const char *fileName) {
    FILE *f = fopen(fileName, "r");
    fseek(f, 0, SEEK_END);
    long fsize = ftell(f);
    rewind(f);
    char *script = malloc(fsize + 1);
    fread(script, 1, fsize, f);
    fclose(f);
    script[fsize] = 0;
    return script;
}

int main(int argc, char **argv) {
    WrenConfiguration config;
    wrenInitConfiguration(&config);
    config.writeFn = &writeFn;
    config.errorFn = &errorFn;
    config.bindForeignClassFn = &bindForeignClass;
    config.bindForeignMethodFn = &bindForeignMethod;
    WrenVM* vm = wrenNewVM(&config);
    const char* module = "main";
    const char* fileName = "HTTPS_Authenticated.wren";
    char *script = readFile(fileName);
    WrenInterpretResult result = wrenInterpret(vm, module, script);
    switch (result) {
        case WREN_RESULT_COMPILE_ERROR:
            printf("Compile Error!\n");
            break;
        case WREN_RESULT_RUNTIME_ERROR:
            printf("Runtime Error!\n");
            break;
        case WREN_RESULT_SUCCESS:
            break;
    }
    wrenFreeVM(vm);
    free(script);
    return 0;
}

zkl

Using cURL to do the heavy lifting, get a XML list of computers connected to my router.

zkl: var ZC=Import("zklCurl")
zkl: var data=ZC().get("http://usr:pw@192.168.1.1/computer_list.xml")
L(Data(1,049),121,0)
zkl: data[0][121,*].text
Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<computers>
<ip_address0>192.168.1.100</ip_address0><host_name0>core-shot
...