An HTTP Server in TECO

The Summer 2012 Retrochallenge Competition is on for the month of July, 2012. I’m going to implement a small web server in TECO and update this page with progress on my implementation.

TECO was the second programming language I learned, after learning two dialects of BASIC (HP 2000 BASIC and DEC BASIC-PLUS). Strictly speaking, TECO isn’t a programming language, it is a command oriented editor with a rich macro facility. You can get a version of TECO for Windows, Linux or Mac from Tom Almy’s TECO page, including full documentation for all the commands. The macro language in TECO is sometimes referred to as a write-only language because most commands in TECO are a single character, including some control characters. The escape key (displayed as $) is used to terminate a command sequence.

Here is an example of a small TECO program that prints the current date and time:

!DATE.TES!
! display the current date and time:                    !
!   ^B == ((year-1900)*16+month)*32+day                 !
!   ^H == (seconds since midnight)/2                    !

EI$
[M[D[Y[W[H[M[S[0[1    ! save used Q-reg's               !

                      ! Get MM/DD/YYYY in Q-reg's M,D,Y !
^B U0                 ! 0.num = encoded date            !
(Q0/32) & 15  UM      ! M.num = month                   !
(Q0)    & 31  UD      ! D.num = day                     !
(Q0/512)      UY      ! Y.num = year                    !

                      ! Get day of week in Q-reg W      !
QD UW                 ! W.num = days this month         !
QM-2  "=  31%W |      ! add days before this month      !
QM-3  "=  59%W |
QM-4  "=  90%W |
QM-5  "= 120%W |
QM-6  "= 151%W |
QM-7  "= 181%W |
QM-8  "= 212%W |
QM-9  "= 243%W |
QM-10 "= 273%W |
QM-11 "= 304%W |
QM-12 "= 334%W '''''''''''
QY & 3 "=             ! correct for leap years          !
  QW-59 ">
    1%W
  '
'
QY+QW+(QY-1/4) U1
Q1-(Q1/7*7) U1
Q1-0"= @^UW%Sunday%    |
Q1-1"= @^UW%Monday%    |
Q1-2"= @^UW%Tuesday%   |
Q1-3"= @^UW%Wednesday% |
Q1-4"= @^UW%Thursday%  |
Q1-5"= @^UW%Friday%    |
Q1-6"= @^UW%Saturday%  '''''''

QM-1"=  @^UM%January%   |  ! get name of month in Q-reg M !
QM-2"=  @^UM%February%  |
QM-3"=  @^UM%March%     |
QM-4"=  @^UM%April%     |
QM-5"=  @^UM%May%       |
QM-6"=  @^UM%June%      |
QM-7"=  @^UM%July%      |
QM-8"=  @^UM%August%    |
QM-9"=  @^UM%September% |
QM-10"= @^UM%October%   |
QM-11"= @^UM%November%  |
QM-12"= @^UM%December%  ''''''''''''

                      ! Get HH:MM:SS in Q-reg's H,N,S   !
^H*2 U0               ! 0.num = second's since midnight !
Q0/3600         UH    ! H.num = hours                   !
QH*3600         U1    ! 1.num = hours (in seconds)      !
(Q0-Q1)/60      UN    ! N.num = minutes                 !
(Q0-Q1)-(QN*60) US    ! S.num = seconds                 !

                      ! Display DAY MONTH DD, YYYY      !
:GW                   ! display DAY                     !
32^T                  ! display <SP>                    !

:GM                   ! display MONTH                   !
32^T                  ! display <SP>                    !

QD-10"< 48^T '        ! display leading zero?           !
QD:=                  ! display DD                      !
44^T                  ! display ,                       !
32^T                  ! display <SP>                    !

1900+QY :=            ! display YYYY                    !
32^T                  ! display <SP>                    !

                      ! Display HH:MM:DD                !
QH-10"< 48^T '        ! display leading zero?           !
QH:=                  ! display HH                      !
58^T                  ! display :                       !
QN-10"< 48^T '        ! display leading zero?           !
QN:=                  ! display MM                      !
58^T                  ! display :                       !
QS-10"< 48^T '        ! display leading zero?           !
QS=                   ! display SS<CR><LF>              !

]1]0]S]M]H]W]Y]D]M    ! restore used Q-reg's            !
$$

As you can see, the single letter commands makes for a pretty cryptic program. Without the comments and whitespace to guide us in the behavior of this program, it is pretty hard to understand. Here is a version of the same program above with the comments and unnecessary whitespace stripped:

!DATE.TEC!EI$[M[D[Y[W[H[M[S[0[1^BU0(Q0/32)&15UM(Q0)&31UD(Q0/512)UYQDUWQM-2"=
31%W|QM-3"=59%W|QM-4"=90%W|QM-5"=120%W|QM-6"=151%W|QM-7"=181%W|QM-8"=212%W|
QM-9"=243%W|QM-10"=273%W|QM-11"=304%W|QM-12"=334%W'''''''''''QY&3"=QW-59">
1%W''QY+QW+(QY-1/4)U1Q1-(Q1/7*7)U1Q1-0"=^UWSunday$|Q1-1"=^UWMonday$|Q1-2"=
^UWTuesday$|Q1-3"=^UWWednesday$|Q1-4"=^UWThursday$|Q1-5"=^UWFriday$|Q1-6"=
^UWSaturday$'''''''QM-1"=^UMJanuary$|QM-2"=^UMFebruary$|QM-3"=^UMMarch$|QM-4"=
^UMApril$|QM-5"=^UMMay$|QM-6"=^UMJune$|QM-7"=^UMJuly$|QM-8"=^UMAugust$|QM-9"=
^UMSeptember$|QM-10"=^UMOctober$|QM-11"=^UMNovember$|QM-12"=^UMDecember$
''''''''''''^H*2U0Q0/3600UHQH*3600U1(Q0-Q1)/60UN(Q0-Q1)-(QN*60)US:GW32^T:GM
32^TQD-10"<48^T'QD:=44^T32^T1900+QY:=32^TQH-10"<48^T'QH:=58^TQN-10"<48^T'QN:=58^T
QS-10"<48^T'QS=]1]0]S]M]H]W]Y]D]M$$

HTTP Server Design

TECO doesn’t have anything like network communication built into it. File and console I/O are the extent of it’s ability to interact with the outside world. My design for a web server written in TECO is simple: edit an input file containing the HTTP request header and body into an HTTP response header and body. This is made easier by the fact that HTTP is largely a text based protocol, so parsing the input and generating the output doesn’t involve manipulating anything beyond the standard 128 ASCII characters.

HTTP supports a number of verbs indicating the desired action by the web browser. Implementing GET and PUT are fairly straightforward for TECO since this involves reading and writing files. Currently, I see no way to implement HEAD or DELETE methods in pure TECO, but it’s possible to have them implemented by something outside of TECO and delegate to them with TECO’s EG command. POST can be implemented by using the URI as the name of a TECO macro file to process the request instead of the standard macro. I’ll implement GET at the very least. PUT will probably not be much more work. I’ll try to get to POST if I can.

The whole thing will have to be invoked through some kind of wrapper that writes out the HTTP request into an input file, invokes TECO, and returns the output file as the HTTP response.

HTTP Date Header

July 15, 2012: The HTTP protocol requires a Date header issued in GMT. TECO provides a way to get the current local date and time. The following macro inserts a proper HTTP Date header into the buffer.

!HTTP-DATE.TEC!
! ------------------------------------------------------------------------- !
! Insert the current date and time as an HTTP Date: header                  !
! ------------------------------------------------------------------------- !
! The date and time varies by computer and OS, encoded in -1EJ:             !
!    -1EJ=256*m+n        Computer (m)        Operating System (n)           !
!                        0         PDP-11    0    RSX-11D                   !
!                                            1    RSX-11M                   !
!                                            2    RSX-11S                   !
!                                            3    IAS                       !
!                                            4    RSTS/E                    !
!                                            5    VAX/VMS                   !
!                                                 (compatibility mode)      !
!                                            6    RSX-11M+                  !
!                                            7    RT-11                     !
!                        1         PDP-8     0    OS/8                      !
!                        2         DEC-10    0    TOPS-10                   !
!                        3         DEC-20    0    TOPS-20                   !
!                        4         VAX-11    0    VAX/VMS                   !
!                                                 (native mode)             !
!                        100       Unix      0    Unix                      !
!                        101       IBM PC    0    MS-DOS                    !
!                                            1    Win32, OS/2               !
!                        102       Amiga     0    AmigaDOS 1.3              !
! ------------------------------------------------------------------------- !

[M [D [Y [H [N [S [0 [1                 ! save used Q-reg's                 !
!   M.num = month in year, 1-12                                             !
!   M.str = days in months as characters adjusted for leap years            !
!   D.num = day in month, 1-31                                              !
!   Y.num = 4-digit year                                                    !
!   Y.str = macro to build M.str from Y.num                                 !
!   H.num = hour in day, 0-23                                               !
!   N.num = minute in day, 0-59                                             !
!   S.num = second in minute, 0-59                                          !
!   S.str = macro to insert 3 chars from 1.str                              !
!   0.num = scratch value                                                   !
!   0.str = macro to insert 2-digit number with leading zero                !
!   1.num = scratch value                                                   !
!   1.str = argument to S.str                                               !

! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< !
! Y.str = macro to build M.str = days in month as characters                !
!         using Y.num = current year                                        !
@^UY\
0J                                      ! Go to start of buffer             !
31@I//                                  ! January                           !
QY&3 "= 29 @I// | 28 @I// '             ! February                          !
31 @I//                                 ! March                             !
30 @I//                                 ! April                             !
31 @I//                                 ! May                               !
30 @I//                                 ! June                              !
31 @I//                                 ! July                              !
31 @I//                                 ! August                            !
30 @I//                                 ! September                         !
31 @I//                                 ! October                           !
30 @I//                                 ! November                          !
31 @I//                                 ! December                          !
0XM                                     ! M.str = temporary string          !
0K                                      ! delete temporary string           !
\
! >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !

! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< !
! S.str = macro to insert 3 chars from 1.str                                !
@^US\
U1                                      ! 1.num = 0-based word index        !
Q1*3 U1                                 ! 1.num = char offset in 1.str      !
3<                                      ! for 3 chars...                    !
    Q1Q1 @I""                           !   insert one char                 !
    1 %1$                               !   1.num++                         !
>                                       ! end                               !
\
! >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !

! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< !
! 0.str = macro to insert two digit number, with leading zero               !
@^U0/
U0                                      ! 0.num = arg                       !
Q0 - 10"<                               ! if 0.num < 10?                    !
    @I"0"                               !   insert zero                     !
'                                       ! end if                            !
Q0\                                     ! insert 0.num                      !
/
! >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> !

^B U0                                   ! 0.num = encoded date              !
-1EJ/256 @O!D1,D8,DT!                   ! handle special date decodings     !
@O!DG!                                  ! handle general date decoding      !

!D1!
Q1 - 7 "=                               ! RT-11?                            !
! ------------------------------------------------------------------------- !
!   RT-11:     ^B = ((((year-2003)*16+month)*32)+day)*32)+(year-1972)&31    !
! ------------------------------------------------------------------------- !
    Q0 "<                               !   if high bit set?                !
        Q0&32767 U0                     !     strip high bit                !
        64 UY                           !     Y.num = corresponding year    !
    |                                   !   else                            !
        0 UY                            !     Y.num = 0                     !
    '                                   !   end if                          !
    (Q0/16384*32) + (Q0&31) + 1972 %Y$  !   Y.num += remaining part of year !
    MY                                  !   M.str = days in months          !
    Q0/32 & 31 UD                       !   D.num = day                     !
    Q0/1024 & 15 UM                     !   M.num = month                   !

    | -1EJ & 255 - 4 "=                 ! if RSTS/E?                        !
! ------------------------------------------------------------------------- !
!   RSTS/E:    ^B = ((year-1970)*1000)+day within year                      !
! ------------------------------------------------------------------------- !
        Q0 - (Q0/1000*1000) UD          !   D.num = day in year             !
        Q0/1000 + 1970 UY               !   Y.num = year                    !
        MY                              !   M.str = days in months          !
        0U0                             !   U.num = 0                       !
        1UM                             !   M.num = January                 !
        12<                             !   for 12 months...                !
            Q0QM U1                     !     1.num = days in month 0.num   !
            QD - Q1 U1                  !     1.num = D.num - 1.num         !
            Q1 ">                       !     if D.num > days in month?     !
                Q1 UD                   !       D.num -= days               !
                1 %M$                   !       M.num++                     !
            '                           !     end if                        !
            1 %0$                       !     0.num++                       !
        >                               !   end                             !
                                        !   D.num = day in month            !
                                        !   M.num = month in year           !
        |                               ! otherwise,                        !
            @O!DG!                      !   general case                    !
        '                               ! end if                            !
    '
'
@O!D!

! ------------------------------------------------------------------------- !
!   OS/8:      ^B = (((month*32)+day)*8)+((year-1970)&7)+k                  !
!                   where k = 4096 if year>1977                             !
!                   and k=0 otherwise                                       !
! ------------------------------------------------------------------------- !
!D8!
Q0 & 7 + 2010 UY                        !   Y.num = year                    !
MY                                      !   M.str = days in months          !
Q0/8 & 31     UD                        !   D.num = day                     !
Q0/256 & 15   UM                        !   M.num = month                   !
@O!D!

! ------------------------------------------------------------------------- !
!   TOPS-10,                                                                !
!   TOPS-20:   ^B = (((year-1964)*12+month-1)*31+day-1)                     !
! ------------------------------------------------------------------------- !
!DT!
Q0 - (Q0/31*31) + 1 UD                  !   D.num = day                     !
Q0/32 U0                                !   0.num /= 32                     !
Q0 - (Q0/12*12) + 1 UM                  !   M.num = month                   !
Q0/12 + 1964 UY                         !   Y.num = year                    !
MY                                      !   M.str = days in months          !
@O!D!

! ------------------------------------------------------------------------- !
!   RSX-11:    ^B = ((year-1900)*16+month)*32+day                           !
!   VAX/VMS:   ^B = ((year-1900)*16+month)*32+day                           !
!   Amiga:     ^B = ((year-1900)*16+month)*32+day                           !
!   Unix:      ^B = ((year-1900)*16+month)*32+day                           !
!   Win32:     ^B = ((year-1900)*16+month)*32+day                           !
!   OS/2:      ^B = ((year-1900)*16+month)*32+day                           !
!   MS-DOS:    ^B = ((year-1900)*16+month)*32+day                           !
! ------------------------------------------------------------------------- !
!DG!
Q0    & 31    UD                        ! D.num = day                       !
Q0/32 & 15    UM                        ! M.num = month                     !
Q0/512 + 1900 UY                        ! Y.num = year                      !
MY                                      ! M.str = days in months            !

!D!
                                        ! Get HH:MM:SS in Q-reg's H,M,S     !
-1EJ/256 @O!T1,T8,TT!                   ! handle special decodings          !
^H*2 U0                                 ! 0.num = seconds since midnight    !
@O!TG!                                  ! handle general decoding           !

! ------------------------------------------------------------------------- !
!   OS/8:      ^H = 0                                                       !
! ------------------------------------------------------------------------- !
!T8!
12 UH                                   ! H.num = 12                        !
00 UN                                   ! N.num = 0                         !
00 US                                   ! S.num = 0                         !
@O!O!                                   ! output time                       !

! ------------------------------------------------------------------------- !
!   RSTS/E:    ^H = minutes until midnight                                  !
! ------------------------------------------------------------------------- !
!T1!
-1EJ -4 "=                              ! RSTS/E?                           !
    (24*60 - ^H)*60 U0                  !   0.num = seconds since midnight  !
    @O!TG!                              !   handle general decoding         !
'
^H*2 U0                                 ! 0.num = seconds since midnight    !
@O!TG!                                  ! do general case                   !

! ------------------------------------------------------------------------- !
!   TOPS-10:   ^H = 60ths of a second since midnight                        !
!                   (or 50ths of a second where 50 Hz power is used)        !
! ------------------------------------------------------------------------- !
!TT!
^H*60 U0                                ! 0.num = seconds since midnight    !
                                        ! fall through to general case      !

! ------------------------------------------------------------------------- !
!   RT-11:     ^H = (seconds since midnight)/2                              !
!   RSX-11:    ^H = (seconds since midnight)/2                              !
!   VAX/VMS:   ^H = (seconds since midnight)/2                              !
!   Amiga:     ^H = (seconds since midnight)/2                              !
!   Unix:      ^H = (seconds since midnight)/2                              !
!   Win32:     ^H = (seconds since midnight)/2                              !
!   OS/2:      ^H = (seconds since midnight)/2                              !
!   MS-DOS:    ^H = (seconds since midnight)/2                              !
! ------------------------------------------------------------------------- !
!TG!
Q0/3600           UH                    ! H.num = hours                     !
QH*3600           U1                    ! 1.num = hours (in seconds)        !
(Q0 - Q1)/60      UN                    ! N.num = minutes                   !
Q0 - Q1 - (QN*60) US                    ! S.num = seconds                   !

!O!
-600 U0                                 ! offset from GMT                   !
Q0 "<                                   ! if offset < 0?                    !
    -Q0 U1                              !   add offset to local time        !
    Q1 - Q1/100*100 %N$                 !   N.num += minute offset          !
    QN - 59 ">                          !   if minutes overflowed?          !
        1 %H$                           !     H.num++                       !
        -60 %N$                         !     N.num -= 60                   !
    '                                   !   end if                          !
    Q1/100 %H$                          !   H.num += hour offset            !
    QH - 23 ">                          !   if hours overflowed?            !
        1 %D$                           !     D.num++                       !
        -24 %H$                         !     H.num -= 24                   !
        QM-1QM U1                       !     1.num = days in month         !
        QD - Q1 ">                      !     if days overflowed?           !
            1 %M$                       !       M.num++                     !
            1 UD                        !       D.num = 1                   !
            QM - 12 ">                  !       if month overflowed?        !
                1 %Y$                   !         Y.num++                   !
                MY                      !         rebuild M.str             !
                1 UM                    !         M.num = 1                 !
            '                           !       end if                      !
        '                               !     end if                        !
    '                                   !   end if                          !
|                                       ! else                              !
                                        !   subtract offset from local time !
    -Q0 + (Q0/100*100) %N$              !   N.num -= minute offset          !
    QN "<                               !   if minutes underflowed?         !
        -1 %H$                          !     H.num--                       !
        60 %N$                          !     N.num += 60                   !
    '                                   !   end if                          !
    -Q0/100 %H$                         !   H.num -= hour offset            !
    QH "<                               !   if hours underflowed?           !
        -1 %D$                          !     D.num--                       !
        24 %H$                          !     H.num += 24                   !
        QD "=                           !     if days underflowed?          !
            -1 %M$                      !       M.num--                     !
            QM "=                       !       if months underflowed?      !
                -1 %Y$                  !         Y.num--                   !
                MY                      !         rebuild M.str             !
                12 UM                   !         M.num = 12                !
                31 UD                   !         D.num = 31                !
            |                           !       else                        !
                QM-1QM UD               !         D.num = last day of month !
            '                           !       end if                      !
        '                               !     end if                        !
    '                                   !   end if                          !
'                                       ! end if                            !

@I"Date: "                              ! Insert Date: header               !
                                        ! Insert DAY, DD Mon YYYY           !

@^U1%SunMonTueWedThuFriSat%
QY U0                                   ! compute day within week from      !
QD U1                                   ! methods of Sakamoto, Lachman,     !
QM-3 "<                                 ! Keith and Craver                  !
    Q0 %1$
    -1 %0$
|
    Q0 - 2 %1$
'
23*QM/9 + Q1 + 4 + (Q0/4) - (Q0/100) + (Q0/400) U0
Q0 - (Q0/7*7)
MS                                      ! Insert DAY                        !
@I", "                                  ! Insert ,<SP>                      !

QD M0                                   ! Insert DD                         !
@I" "                                   ! Insert <SP>                       !

@^U1%JanFebMarAprMayJunJulAugSepOctNovDec%
QM - 1 MS                               ! Insert name of month              !
@I" "                                   ! Insert <SP>                       !

QY\                                     ! Insert YYYY                       !
@I" "                                   ! Insert <SP>                       !

                                        ! Insert HH:MM:SS                   !
QH M0                                   ! Insert HH                         !
@I":"                                   ! Insert :                          !
QN M0                                   ! Insert MM                         !
@I":"                                   ! Insert :                          !
QS M0                                   ! Insert SS                         !
@I" GMT
"                                       ! Insert <SP>GMT<CR>                !
]1 ]0 ]S ]N ]H ]Y ]D ]M                 ! restore used Q-reg's              !
$$

Some observations from doing this little exercise:

  • nQq extracts the nth character code from the string portion of Q-register q. Using another Q-register as the numeric argument to this command confused the parser of my TECO, hence the use of an intermediate Q-register by doing ‘Q0QM U1‘. It didn’t uniformly confuse my TECO, so there were some cases where I could use QqQq directly in some expressions. This might cause a portability issue for other TECOs.
  • I could make this macro much shorter if I hard-coded the date and time decoding for a particular OS.
  • I could make this macro much shorter if I hard-coded the time zone offset from GMT, or even just lied and pretended my web server’s local time was GMT.
  • Indexing the string %SunMonTueWedThuFriSatSun% and inserting 3 chars was much less code than doing a comparison for each value.
  • Extracting repeated code into a macro was most effective in reducing squished size.
  • The string portion of a Q-register can be viewed as an array of bytes; I use this to build an array of days in each month. This reduced the size of code computing day-in-a-year from day/month and day/month from day-in-a-year. The array is also used to handle underflow and overflow when applying the GMT offset.
  • I made the labels reasonably small in order to squeeze out more bytes, but since I don’t use more than 96 labels, I could have reduced them to a single character. I decided against this.
  • SQU.TEC will recursively squish my macro definitions, but I kept running into a problem with the day and month strings I was loading into 1.str until I re-read the SQU.TES source and learned that if I use % as the delimiter, then SQU will not treat these Q-register string loads as macro definitions, but as literal text.
  • Computed goto @O!tag0,tag1,tag2! made it easier to handle decoding the different date/time formats in different environments.
  • You can’t insert or append character codes directly into a Q-register, but you can insert character codes into the buffer and pull a portion of the buffer into a Q-register.
  • DATE.TES reports the wrong day of the week, probably because it uses an algorithm that is no longer valid for years > 1999. I switched to the Sakamoto, Lachman, Keith and Craver algorithm published in Wikipedia. This also eliminated me having to compute day-within-year.
  • n%q can be used to add n to Q-register q, avoiding the Qq + n Uq phrase, but n%q leaves the result as a numeric argument to the next command, so ESCs must be inserted to gobble these up.
  • TECO numeric expressions have no operator precedence and are evaluated strictly left to right. Sometimes this means that extra parenthesis are necessary to get the right evaluation order and other times parenthesis can be omitted and still retain the proper evaluation order.

HTTP Wrapper

July 24th, 2012: TECO only knows how to consume and produce file oriented I/O and has no socket facility. In order to act as an HTTP server, I will need to prepare a small server program that accepts the HTTP request, writes it to a file, invokes TECO to produce the response and transmits the response. I worked up a small C++ program to do the job and ran into a few small obstacles. First, HTTP/1.1 keeps the socket open for multiple requests to the same host to avoid TCP/IP slow-startup costs incurred by making each HTTP request correspond to a new TCP/IP connection.  As a result, the simple wrapper will just close the connection on the client when it is done sending the response, in order to simplify the wrapper.

Secondly, the wrapper will need to peek into the headers to determine when it has read the entirety of the request message.  For instance, a POST request will transmit both request headers and a request body with the length of the body declared in the Content-Length request header.  The wrapper will need to parse out the content length from the request header for a POST request.  For a GET request, the wrapper can simply assume that once the header is complete, then it has the entire request.

There are additional operational constraints that will be imposed on this server due to the way in which TECO operates on a buffer-at-a-time for editing.  TECO was created for very small memory environments without virtual memory and operates by bringing a portion of the input into an editing buffer.  Editing commands operate on the current buffer and then write out the modified buffer contents to the output.  As mentioned above, the Content-Length header on a POST request specifies the length of the HTTP message body and in a response the same header is used to indicate the size of the response body, i.e. the size of the delivered content.  So, for purposes of simplifying the implementation, the TECO http server will assume that the entire content can fit into the buffer.  Otherwise, TECO http would need to pass over the content twice, once just to count the size, and a second time to write it to the output file.

Challenge Ended

August 2nd, 2012: The retrocomputing challenge ended on July 31st and I didn’t quite have time to finish the HTTP server in time for the challenge deadline. Ironically, issuing the date header and having the wrapper were the major chunks of code that needed to be written, so I finished the majority of the code. I hope to finish this off in the next few weeks, but it might take the whole of August with summer trips and other things vying for my time.

3 Responses to “An HTTP Server in TECO”

  1. An HTTP Server in TECO, Part 2 | Legalize Adulthood! Says:

    […] summer for the Summer 2012 Retrochallenge Competition I made some progress on an HTTP server in TECO. While I didn’t quite finish, I did make considerable progress. For this year’s summer […]

    Like

  2. Paul Koning Says:

    BTW, you said that “TECO is not a programming language”. I wouldn’t have said that. Admittedly the boundary between scripting machinery and programming language is a bit fuzzy, but… I would argue that anything in which you can calculate pi is a programming language. You have seen the famous pi.tec, I hope?

    Like


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: