/pliant/protocol/http/chunked.pli
 
 1  # Copyright  Hubert Tonneau  hubert.tonneau@pliant.cx 
 2  # 
 3  # This program is free software; you can redistribute it and/or 
 4  # modify it under the terms of the GNU General Public License version 2 
 5  # as published by the Free Software Foundation. 
 6  # 
 7  # This program is distributed in the hope that it will be useful, 
 8  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 9  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 10  # GNU General Public License for more details. 
 11  # 
 12  # You should have received a copy of the GNU General Public License 
 13  # version 2 along with this program; if not, write to the Free Software 
 14  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 15   
 16  module "/pliant/language/unsafe.pli" 
 17  module "/pliant/language/stream.pli" 
 18  module "/pliant/language/stream/filesystembase.pli" 
 19  module "/pliant/language/stream/multi.pli" 
 20  module "/pliant/language/stream/openmode.pli" 
 21   
 22   
 23  type ChunkedStreamDriver 
 24    field Link:Stream s 
 25    field Int flags 
 26    field Int read_remain ; field CBool read_eof 
 27    field Int read_counter write_counter 
 28    field CBool browser 
 29  StreamDriver maybe ChunkedStreamDriver 
 30   
 31   
 32  function unhexa s -> i 
 33    arg Str s ; arg Int i 
 34    := 0 
 35    for (var Int j) s:len-1 
 36      var Int := s:number 
 37      if c>="0":0:number and c<="9":0:number 
 38        := i*16+(c-"0":0:number) 
 39      eif c>="A":0:number and c<="F":0:number 
 40        := i*16+(c-"A":0:number+10) 
 41      eif c>="a":0:number and c<="f":0:number 
 42        := i*16+(c-"a":0:number+10) 
 43      eif c=" ":number 
 44        return 
 45      else 
 46        return undefined 
 47   
 48  method drv read buf mini maxi -> red 
 49    oarg_rw ChunkedStreamDriver drv ; arg Address buf ; arg Int mini maxi red 
 50    red := 0 
 51    while red<mini 
 52      if drv:read_eof 
 53        return 
 54      eif drv:read_remain>0 
 55        drv:read_available (var Address adr) (var Int size) (min maxi-red drv:read_remain) 
 56        memory_copy adr (buf translate Byte red) size ; red += size ; drv read_remain -= size 
 57        drv read_counter += size 
 58      eif drv:browser 
 59        var Str := drv:readline 
 60        if not (parse word:"b" drv:read_remain) 
 61          drv:read_remain=undefined 
 62          drv:unreadline l 
 63      else # HTTP chunking 
 64        if drv:read_remain<>undefined 
 65          drv:readline 
 66        drv read_remain := unhexa drv:s:readline 
 67        if drv:read_remain=0 
 68          drv:readline 
 69        if drv:read_remain<=0 
 70          drv read_eof := true 
 71   
 72   
 73  method drv write buf mini maxi -> written 
 74    oarg_rw ChunkedStreamDriver drv ; arg Address buf ; arg Int mini maxi written 
 75    if drv:browser 
 76      drv:writechars "b "+string:maxi+"[lf]" 
 77      drv:raw_write buf maxi 
 78    else 
 79      drv:writechars (string maxi "radix 16")+"[cr][lf]" 
 80      drv:raw_write buf maxi 
 81      drv:writechars "[cr][lf]" 
 82    drv write_counter += maxi 
 83    written := shunt drv:s=success maxi 0 
 84   
 85   
 86  method drv flush level -> status 
 87    oarg_rw ChunkedStreamDriver drv ; arg Int level ; arg Status status 
 88    drv:flush level 
 89    status := shunt drv:s=success success failure 
 90   
 91   
 92  method drv close -> status 
 93    oarg_rw ChunkedStreamDriver drv ; arg ExtendedStatus status 
 94    if (drv:flags .and. out)<>0 
 95      if drv:browser 
 96        void 
 97      else 
 98        drv:writechars "0[cr][lf]" 
 99        drv:writechars "[cr][lf]" 
 100    status := success 
 101   
 102   
 103  method drv query command stream answer -> status 
 104    oarg_rw ChunkedStreamDriver drv ; arg Str command ; arg_rw Stream stream ; arg_w Str answer ; arg ExtendedStatus status  
 105    if command="read_counter" 
 106      answer := string drv:read_counter 
 107      status := success 
 108    eif command="write_counter" 
 109      answer := string drv:write_counter 
 110      status := success 
 111    else 
 112      status := drv:s:stream_driver query command drv:answer 
 113   
 114   
 115  method drv configure command stream -> status 
 116    oarg_rw ChunkedStreamDriver drv ; arg Str command ; arg_rw Stream stream ; arg ExtendedStatus status 
 117    if (command parse word:"read_counter" (var Int counter)) 
 118      drv read_counter := counter 
 119      status := success 
 120    eif (command parse word:"write_counter" (var Int counter)) 
 121      drv write_counter := counter 
 122      status := success 
 123    else 
 124      status := drv:s:stream_driver configure command drv:s 
 125   
 126   
 127 
 
 128   
 129   
 130  type ChunkedFileSystem 
 131    void 
 132  FileSystem maybe ChunkedFileSystem 
 133   
 134   
 135  method fs open name options flags stream support -> status 
 136    oarg_rw ChunkedFileSystem fs ; arg Str name options ; arg Int flags ; arg_rw Stream stream support ; arg ExtendedStatus status 
 137    var Link:Stream s 
 138    if exists:support 
 139      :> support 
 140    else 
 141      var Link:Stream :> new Stream 
 142      open name options (flags .and. in+out+safe) 
 143      if s=failure 
 144        return failure 
 145    var Link:ChunkedStreamDriver drv :> new ChunkedStreamDriver 
 146    drv :> s 
 147    drv flags := flags 
 148    drv read_remain := undefined ; drv read_eof := false 
 149    drv read_counter := 0 
 150    drv write_counter := 0 
 151    drv browser := options option "pliant_browser_chunking" 
 152    stream stream_driver :> drv 
 153    status := success 
 154   
 155   
 156  gvar ChunkedFileSystem chunked_file_system 
 157  pliant_multi_file_system mount "chunked:" "" chunked_file_system 
 158   
 159