17
\$\begingroup\$

Write a program that accepts HTTP requests on any port of your choice above 1024, and responds to requests on any URL of your choice with its own source code. It must work with, at least, Firefox and Chrome. The code should be delivered as text/plain (removed requirement because none of the answers but one met it) with no formatting. There is no restriction on the URL, except that it must not be used to encode any portion of the code; serving on the root is encouraged and likely the shortest solution, but is not required.

Standard quine restrictions apply. Web server frameworks are allowed, but are considered separate languages, so, for example, a Python + Flask answer does not compete with a stdlib-only Python answer.

Bonus for HTTPS support:

HTTPS HTTP Bonus
No Yes None
Yes No 10%
Yes Yes 15%
Yes Redirects to HTTPS 20%

If you do include HTTPS support, you may access the certificate by any reasonable means.

\$\endgroup\$
6
  • 2
    \$\begingroup\$ Does it need to respond to multiple requests? \$\endgroup\$
    – gsitcia
    Commented Nov 30, 2023 at 3:12
  • \$\begingroup\$ @gsitcia no, except that to claim the 20% bonus for redirecting HTTP to HTTPS, it must be able to handle the initial HTTP request and the resulting HTTPS request. Otherwise, it's okay if it closes after one request. \$\endgroup\$
    – Someone
    Commented Nov 30, 2023 at 3:59
  • 1
    \$\begingroup\$ Is it okay if the port is chosen randomly at startup? \$\endgroup\$
    – corvus_192
    Commented Nov 30, 2023 at 19:44
  • \$\begingroup\$ @corvus_192 that is okay, as long as there is some indication of what port is used, such as printing it to stdout \$\endgroup\$
    – Someone
    Commented Nov 30, 2023 at 19:47
  • 1
    \$\begingroup\$ Is it cheating to just serve the source file? \$\endgroup\$ Commented Dec 5, 2023 at 14:00

11 Answers 11

10
\$\begingroup\$

Javascript (Node.js), 77 bytes

(f=x=>require('http').createServer((_,x)=>x.end(`(f=${f})()`)).listen(1e4))()
\$\endgroup\$
3
  • \$\begingroup\$ 76 bytes with express: (f=x=>require('express')().get('',(_,r)=>r.end((f=${f})())).listen(1e4))() \$\endgroup\$
    – corvus_192
    Commented Nov 30, 2023 at 19:47
  • \$\begingroup\$ @corvus_192 Not vanilla and Web server frameworks are allowed, but are considered separate languages \$\endgroup\$
    – l4m2
    Commented Dec 1, 2023 at 0:31
  • \$\begingroup\$ I know, but the code is so similar, I didn't want to post it as a separate answer. \$\endgroup\$
    – corvus_192
    Commented Dec 1, 2023 at 11:28
7
\$\begingroup\$

Python 3, 176 bytes

_='_=%r;a=%r;exec(a)';a="from socket import*;s=socket();s.bind(('',9000));s.listen()\nwhile 1:q,c=s.accept();q.send(b'HTTP/1.0\\n\\n'+(_%(_,a)).encode());q=q.recv(999)";exec(a)

Listens to any requests to localhost:9000.

Only listening for one request saves 11 bytes

165 bytes

_='_=%r;a=%r;exec(a)';a="from socket import*;s=socket();s.bind(('',9000));s.listen();q,c=s.accept();q.send(b'HTTP/1.0\\n\\n'+(_%(_,a)).encode());q.recv(999)";exec(a)

Both browsers (Firefox 120.0 & Chromium 119.0.6045.159) seem to be happy to accept responses with no status code.

147 bytes (only Firefox)

_='_=%r;a=%r;exec(a)';a="from socket import*;s=socket();s.bind(('',9000));s.listen();q,c=s.accept();q.send((_%(_,a)).encode());q.recv(999)";exec(a)

Firefox still supports HTTP/0.9

146 bytes (only Chromium)

_='_=%r;a=%r;exec(a)';a="from socket import*;s=socket();s.bind(('',9000));s.listen();s.accept()[0].send(b'HTTP\\n\\n'+(_%(_,a)).encode())";exec(a)

Chromium doesn't seem to require the '/1.0' part, and also doesn't care if the server closes the connection early (?)

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Can you replace 9000 with 9e3 or even -1 for port 65535? \$\endgroup\$
    – ATaco
    Commented Nov 30, 2023 at 3:57
  • \$\begingroup\$ @ATaco I just tried it, 9e3 complains about being a float, and -1 gives an OverflowError \$\endgroup\$
    – gsitcia
    Commented Nov 30, 2023 at 4:36
  • \$\begingroup\$ Huh, I wonder why Firefox requires Content-Length? \$\endgroup\$
    – Neil
    Commented Nov 30, 2023 at 8:31
  • 1
    \$\begingroup\$ Actually testing it locally it's intermittent... \$\endgroup\$
    – Neil
    Commented Nov 30, 2023 at 10:51
  • 1
    \$\begingroup\$ You can remove the space after import in from socket import *. \$\endgroup\$ Commented Nov 30, 2023 at 22:07
7
\$\begingroup\$

Python 3 + http.server, 134 95 bytes

exec(b:="import os;open('.txt','w').write('exec(b:=%r)'%b);os.system('python -m http.server')")

Uses a simple Exec quine and writes the contents of it to .txt and then launches a simple webserver in the current folder via the python -m http.server tool. Hosts on port 8000 at /.txt

Very rarely use Python, so it might be golfable...

enter image description here

\$\endgroup\$
6
  • 2
    \$\begingroup\$ I haven't tested it, but knowing Python, can't you remove the space at ) as? \$\endgroup\$ Commented Nov 30, 2023 at 7:45
  • 1
    \$\begingroup\$ You can provide a single string for the call argument: call(['python','-m','http.server']) -> call('python -m http.server'), removing 6 bytes. \$\endgroup\$
    – SevC_10
    Commented Nov 30, 2023 at 17:27
  • \$\begingroup\$ why the very long subprocess.call instead of os.system? \$\endgroup\$
    – user20574
    Commented Dec 1, 2023 at 18:42
  • 1
    \$\begingroup\$ @Somebody Unfortunately has to be .txt as otherwise it tries to download the file, rather than render it. \$\endgroup\$
    – ATaco
    Commented Dec 2, 2023 at 4:59
  • 1
    \$\begingroup\$ @ATaco I think the challenge was to return an HTTP response with the source code, so IMO downloading is valid \$\endgroup\$
    – Seggan
    Commented Dec 3, 2023 at 3:09
6
\$\begingroup\$

Python + Flask, 151 bytes

from flask import*;a=Flask('');s="from flask import*;a=Flask('');s=%s\[email protected]('/')\ndef i():return s%%repr(s)"
@a.route('/')
def i():return s%repr(s)

Doesn't show newlines as it's text/html. Visible on localhost:5000 and/or 127.0.0.1:5000. The obvious python and flask solution.

To be executed as a flask app. For example (on windows at least), assuming the file is called flask_app.py:

> set FLASK_APP=flask_app
> flask run

enter image description here

\$\endgroup\$
4
  • \$\begingroup\$ Can't be bothered to test it, but does this work by any chance? \$\endgroup\$ Commented Nov 30, 2023 at 4:55
  • 1
    \$\begingroup\$ Why don't you use exec to run thethe code in the string and avoid having to duplicate it? \$\endgroup\$
    – The_spider
    Commented Nov 30, 2023 at 20:26
  • \$\begingroup\$ "Doesn't show newlines as it's text/plain." What? did you mean text/html? \$\endgroup\$
    – Oskar Skog
    Commented Dec 1, 2023 at 9:26
  • \$\begingroup\$ @OskarSkog yes, I indeed meant text/html \$\endgroup\$
    – lyxal
    Commented Dec 1, 2023 at 9:48
5
\$\begingroup\$

JavaScript (Deno), 60 52 bytes

function f(){Deno.serve(_=>new Response(f+"f()")}f()

Try it at the Deno Deploy Playground! (Outdated).

Saved 5 bytes by using a function declaration instead of an arrow function, because Deno runs in strict mode where you need let in variable declarations:

let f=_=>…`let f=${f};f()`…;f()
function f(){…f+"f()"…}f()
// allowed in Node, but not in Deno:
f=_=>…`f=${f};f()`…;f()

Here's an alternate version that doesn't use function stringifying, stolen slightly modified from Don Hastings's wonderful quine, for 88 bytes:

let Q="let q=Q.link()[8];Deno.serve(()=>new Response(`let Q=${q+Q+q};eval(Q)`))";eval(Q)

Try it at the Deno Deploy Playground!

\$\endgroup\$
5
\$\begingroup\$

Lua + LuaSockets, 138 bytes.

b="t=require('socket').tcp()t:bind('*',-1)t:listen()c=t:accept()c:receive()c:send(('HTTP/1.0 200\\n\\nb=%qload(b)()'):format(b))"load(b)()

Stores the main code in b and loads it, then wraps it in ('...b=%qload(b)()'):format(b) to quine it. The webserver listens for any TCP connection on port 65535 (-1) and just immediately dumps the bare-minimum HTTP response to it.

enter image description here

\$\endgroup\$
5
\$\begingroup\$

Racket #lang web-server/insta, 199 bytes

#lang web-server/insta (define-syntax-rule(S n f)(define n(f'(S n f))))(S start (λ (s) (λ r (response/xexpr (~a "#lang web-server/insta (define-syntax-rule(S n f)(define n(f'(S n f))))" (~s s))))))

Running the program (e.g. with racket golf.rkt or in DrRacket) prints something like:

Your Web application is running at http://localhost:34163/servlets/standalone.rkt.
Stop this program at any time to terminate the Web Server.

and automatically launches your default browser with the page. Stopping the program (e.g. with Ctrl-C or DrRacket's Stop button) prints:


Web Server stopped.

Depending on your definition of "standard library", web-server/insta might be part of Racket's standard library. It is included in the "main distribution" you'd download from https://download.racket-lang.org.

HTTPS Only, 241 bytes

#lang web-server (define-syntax-rule(S s)(s'(S s)))(S (λ (s) (local-require web-server/servlet-env) (serve/servlet (λ r (response/xexpr (~a "#lang web-server (define-syntax-rule(S s)(s'(S s)))" (~s s)))) #:ssl? #t #:server-root-path ".")))

This uses server-cert.pem and private-key.pem from the current directory. It serves on https://localhost:8000/servlets/standalone.rkt.

HTTP→HTTPS, 356 bytes

#lang web-server (define-syntax-rule(S s)(s'(S s)))(S (λ (s) (local-require web-server/servlet-env) (thread (λ () (serve/servlet (λ r (redirect-to "https://localhost:8443/servlets/standalone.rkt"))))) (serve/servlet (λ r (response/xexpr (~a "#lang web-server (define-syntax-rule(S s)(s'(S s)))" (~s s)))) #:port 8443 #:ssl? #t #:server-root-path ".")))

Same certificate configuration as above, but listens on http://localhost:8000/servlets/standalone.rkt and https://localhost:8443/servlets/standalone.rkt.

Original: With text/plain, 263 bytes

#lang web-server/insta (define-syntax-rule (S n f) (define n (f '(S n f)))) (S start (λ (s) (λ r (response/output #:mime-type #"text/plain;charset=utf-8" (λ (o) (fprintf o "#lang web-server/insta (define-syntax-rule (S n f) (define n (f '(S n f)))) ~s" s))))))
\$\endgroup\$
2
  • \$\begingroup\$ It's a shame we can't save a few more bytes by removing spaces in the body of start; I tried, and (I think because of the macro) the response puts them back in. \$\endgroup\$ Commented Dec 5, 2023 at 14:47
  • \$\begingroup\$ @D.BenKnoble I tried, too: the issue is that write emits conventional whitespace, not the minimum possible whitespace. \$\endgroup\$ Commented Dec 5, 2023 at 17:10
2
\$\begingroup\$

PowerShell Core, 149 bytes

$f={($h=[Net.HttpListener]::new()).Prefixes.Add("http://*:9090/")
$h|% s*t
(($r=$h|% G*t|% R*e)|% o*).Write([byte[]]("`$f={$f}"|% t*y))
$r.Close()}

Run it using &$f
Listens on port 9090
Replies only once and does not free the port

Example output

\$\endgroup\$
2
\$\begingroup\$

Rust, 385 bytes

use std::io::*;fn main(){write!(std::net::TcpListener::bind("127.0.0.1:8080").unwrap().accept().unwrap().0,r"HTTP/1.1 200
Content-Type:text/plain
Content-Length:385

{1}{1}{}","\x22#);}",r#"use std::io::*;fn main(){write!(std::net::TcpListener::bind("127.0.0.1:8080").unwrap().accept().unwrap().0,r"HTTP/1.1 200
Content-Type:text/plain
Content-Length:385

{1}{1}{}","\x22#);}",r#""#);}

When run as the main.rs file in a cargo project with cargo run, this program waits until you go to 127.0.0.1:8080 in your browser (this is what accept() does) and then sends over its source code and ends.

\$\endgroup\$
1
\$\begingroup\$

C (gcc -lws2_32 + winsock2.h), 408 bytes

Z;main(){char*S,Q[16]={2,0,4,1},*M=malloc(999);WSAStartup(9,M);sprintf(M,S="HTTP/1.1 200 OK%c%cContent-Length: 408%c%c%c%cZ;main(){char*S,Q[16]={2,0,4,1},*M=malloc(999);WSAStartup(9,M);sprintf(M,S=%c%s%c,13,10,13,10,13,10,34,S,34);bind(Z=socket(2,1,0),Q,16);for(listen(Z,3);;)send(accept(Z,Q,0),M,448,0);}",13,10,13,10,13,10,34,S,34);bind(Z=socket(2,1,0),Q,16);for(listen(Z,3);;)send(accept(Z,Q,0),M,448,0);}

This uses the Windows Socket 2 API. I have made many questionable choices for the sake of the golf, so there is likely some instability. Listens to an arbitrary number of HTTP requests on port 1025. Compiled with gcc server.c -o server -lws2_32 (e.g.).

Verification

In Firefox:

A picture of the Quine in action on Firefox, showing the full code from earlier.

[![A picture of the Quine in action on Firefox, showing the full code from earlier.][2]][2]

Here is the Ruby test harness I used to verify integrity:

require "net/http"
puts "Waiting for server to start..."
server_process = IO.popen("server.exe") { |server|
    3.times { |i|
        response = Net::HTTP.get_response(URI("http://localhost:1025")).body
        puts "Response ##{i} obtained:"
        puts response
        
        puts "Same as server.c?"
        puts File.read("server.c") == response
    }

    puts "Killing server..."
    Process.kill("KILL", server.pid)
}

Which, when run:

λ ruby test-server.rb
Waiting for server to start...
Response #0 obtained:
Z;main(){char*S,Q[16]={2,0,4,1},*M=malloc(999);WSAStartup(9,M);sprintf(M,S="HTTP/1.1 200 OK%c%cContent-Length: 408%c%c%c%cZ;main(){char*S,Q[16]={2,0,4,1},*M=malloc(999);WSAStartup(9,M);sprintf(M,S=%c%s%c,13,10,13,10,13,10,34,S,34);bind(Z=socket(2,1,0),Q,16);for(listen(Z,3);;)send(accept(Z,Q,0),M,448,0);}",13,10,13,10,13,10,34,S,34);bind(Z=socket(2,1,0),Q,16);for(listen(Z,3);;)send(accept(Z,Q,0),M,448,0);}
Same as server.c?
true
Response #1 obtained:
Z;main(){char*S,Q[16]={2,0,4,1},*M=malloc(999);WSAStartup(9,M);sprintf(M,S="HTTP/1.1 200 OK%c%cContent-Length: 408%c%c%c%cZ;main(){char*S,Q[16]={2,0,4,1},*M=malloc(999);WSAStartup(9,M);sprintf(M,S=%c%s%c,13,10,13,10,13,10,34,S,34);bind(Z=socket(2,1,0),Q,16);for(listen(Z,3);;)send(accept(Z,Q,0),M,448,0);}",13,10,13,10,13,10,34,S,34);bind(Z=socket(2,1,0),Q,16);for(listen(Z,3);;)send(accept(Z,Q,0),M,448,0);}
Same as server.c?
true
Response #2 obtained:
Z;main(){char*S,Q[16]={2,0,4,1},*M=malloc(999);WSAStartup(9,M);sprintf(M,S="HTTP/1.1 200 OK%c%cContent-Length: 408%c%c%c%cZ;main(){char*S,Q[16]={2,0,4,1},*M=malloc(999);WSAStartup(9,M);sprintf(M,S=%c%s%c,13,10,13,10,13,10,34,S,34);bind(Z=socket(2,1,0),Q,16);for(listen(Z,3);;)send(accept(Z,Q,0),M,448,0);}",13,10,13,10,13,10,34,S,34);bind(Z=socket(2,1,0),Q,16);for(listen(Z,3);;)send(accept(Z,Q,0),M,448,0);}
Same as server.c?
true
Killing server...

Explanation

Using fairly standard quining techniques, although my gcc on Windows does not support the POSIX extension for referencing existing *printf arguments (as in this quine, so we must duplicate quite a few constants. At one point, I tried using unprintable characters in multiple places (`Q="\x02\x00''"), but that seemed to not work well with browsers interfacing with the server.

Here is an expanded version, producing the same output as above (so no longer a quine itself), but commented:

// our socket description integer
Z;
// the server code contained here
main() {
    char
        // our format string to be passed into sprintf
        *S,
        // shorthand for our struct sockaddr_in, which is passed to bind and accept
        // struct sockaddr_in address = { .sin_family = AF_INET /*=2*/, .sin_port = htons(1025) /*=0x0401*/ };
        // [NOTE 1]
        Q[16] = { 2, 0, 4, 1 },
        // M serves two purposes: 1. to be a sprintf buffer and 2. to be allocated memory to allow WSAStartup to run without crashing
        *M = malloc(999);
    // usually, wVersionRequired is version of windows sockets required (e.g. 2.1 would be 0x0201 = 513), and would be expressed like MAKEWORD(2,3)
    // while wVersionRequired can't be 0, from testing, 9 seems to work.
    WSAStartup(9, M);
    // the main quine section
    sprintf(
        // the message buffer
        M,
        // the format string
        S = "HTTP/1.1 200 OK%c%cContent-Length: 412%c%c%c%cZ;main(){char*S,Q[16]={2,0,4,1},*M=malloc(999);WSAStartup(514,M);sprintf(M,S=%c%s%c,13,10,13,10,13,10,34,S,34);bind(Z=socket(2,1,0),Q,16);for(listen(Z,3);;)send(accept(Z,Q,0),M,452,0);}",
        // \r\n after 200 OK
        13, 10,
        // \r\n\r\n after headers
        13, 10, 13, 10
        // " followed by our string followed by ",
        34, S, 34,
    );
    // binds our socket to our target address
    bind(
        // creates a socket with a particular configuration.
        // socket(
        //    address family specification; AF_INET == 2, and represents IPv4
        //    the socket type specification; SOCK_STREAM == 1, and represents two-way connections
        //    the protocol subtype; 0, since we don't need to specify anything further
        // )
        // returns a socket description integer
        Z = socket(2,1,0),
        // the string from earlier, reinterpreted as an address struct
        Q,
        // the size of the address struct; expected to be 16
        16
    );
    // infinite loop
    for(
        // but first, to save a semicolon, start listening on our socket
        // we arbitrarily choose 3 as a backlog queue size
        listen(Z, 3);
        ;
    ) {
        // reply to the request with the message
        send(
            // accept a request on the address for our socket
            accept(Z, Q, 0),
            // the message to report
            M,
            // its length
            452,
            // flags; none chosen
            0
        );
    }
}

Note 1: We can omit the more precise property specification .sin_addr = { .s_addr = INADDR_ANY } as INADDR_ANY == 0. If we did need it, we do have the golfy option Q={2,1025,{0}}.

\$\endgroup\$
1
  • \$\begingroup\$ I just noticed it doesn't have to respond to multiple requests. I'll change the code in a bit. \$\endgroup\$ Commented Mar 25 at 0:18
-1
\$\begingroup\$

Bash + ncat (from nmap), 106 bytes

h='HTTP/2\r\n\r\n';s='h=\47%s\47;s=\47%s\47;printf $h$s $h $s|ncat -lp2222';printf $h$s $h $s|ncat -lp2222
\$\endgroup\$
2
  • 1
    \$\begingroup\$ it does not return the souce code \$\endgroup\$
    – matteo_c
    Commented Dec 2, 2023 at 17:44
  • \$\begingroup\$ It does for me in Firefox and Chrome. \$\endgroup\$
    – corvus_192
    Commented Dec 3, 2023 at 11:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.