Changeset 753
- Timestamp:
- 01/11/06 17:32:22 (3 years ago)
- Files:
-
- trunk/mango/http/client/HttpClient.d (modified) (3 diffs)
- trunk/mango/http/server/HttpCookies.d (modified) (8 diffs)
- trunk/mango/http/server/HttpHeaders.d (modified) (4 diffs)
- trunk/mango/http/server/HttpParams.d (modified) (4 diffs)
- trunk/mango/http/server/HttpRequest.d (modified) (7 diffs)
- trunk/mango/http/server/HttpTokens.d (modified) (1 diff)
- trunk/mango/http/utils/TokenStack.d (modified) (5 diffs)
- trunk/mango/io/Buffer.d (modified) (6 diffs)
- trunk/mango/io/Properties.d (modified) (2 diffs)
- trunk/mango/io/Stdin.d (modified) (2 diffs)
- trunk/mango/io/TextReader.d (modified) (7 diffs)
- trunk/mango/io/model/IBuffer.d (modified) (2 diffs)
- trunk/mango/test/unittest.d (modified) (11 diffs)
- trunk/mango/text/Iterator.d (added)
- trunk/mango/text/LineIterator.d (added)
- trunk/mango/text/LineStream.d (deleted)
- trunk/mango/text/LineToken.d (deleted)
- trunk/mango/text/QuoteIterator.d (added)
- trunk/mango/text/QuotedStream.d (deleted)
- trunk/mango/text/QuotedToken.d (deleted)
- trunk/mango/text/RegexIterator.d (added)
- trunk/mango/text/RegexStream.d (deleted)
- trunk/mango/text/RegexToken.d (deleted)
- trunk/mango/text/SimpleStream.d (deleted)
- trunk/mango/text/SimpleToken.d (deleted)
- trunk/mango/text/Token.d (deleted)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/mango/http/client/HttpClient.d
r752 r753 47 47 48 48 private import mango.io.Uri, 49 mango.io.Token,50 49 mango.io.Buffer, 50 mango.io.Exception, 51 51 mango.io.SocketConduit, 52 mango.io.Exception,53 mango.io.Tokenizer,54 52 mango.io.DisplayWriter; 53 54 private import mango.text.LineIterator; 55 55 56 56 private import mango.http.utils.TokenTriplet; … … 438 438 439 439 // Token for initial parsing of input header lines 440 CompositeToken line = new CompositeToken (Tokenizers.line,input);440 auto line = new LineIterator (input); 441 441 442 442 // skip any blank lines 443 while (line.next () && line.getLength() ==0)443 while (line.next && line.get.length is 0) 444 444 {} 445 445 … … 452 452 453 453 // read response line 454 responseLine.parse (line. toString);454 responseLine.parse (line.get); 455 455 456 456 // parse headers trunk/mango/http/server/HttpCookies.d
r625 r753 40 40 module mango.http.server.HttpCookies; 41 41 42 private import mango.text.Text; 43 44 private import mango.io.Token, 45 mango.io.Buffer, 46 mango.io.Tokenizer; 42 private import mango.io.Buffer; 43 44 private import mango.text.Text, 45 mango.text.Iterator; 47 46 48 47 private import mango.io.model.IWriter, … … 348 347 { 349 348 private bool parsed; 350 private Cookie cookie;351 private IBuffer buffer;352 349 private CookieStack stack; 350 private CookieParser parser; 353 351 private HttpHeaders headers; 354 352 355 private static CookieParser parser;356 357 /**********************************************************************358 359 Setup the parser for server-side cookies360 361 **********************************************************************/362 363 static this ()364 {365 parser = new CookieParser ();366 }367 368 353 /********************************************************************** 369 354 … … 375 360 { 376 361 this.headers = headers; 377 378 // setup an empty buffer for later use379 buffer = new Buffer;380 362 381 363 // create a stack for parsed cookies 382 364 stack = new CookieStack (10); 365 366 // create a parser 367 parser = new CookieParser (stack); 383 368 } 384 369 … … 391 376 void write (IWriter writer) 392 377 { 393 foreach (Cookie cookie; parse ())378 foreach (Cookie cookie; parse) 394 379 writer.put (cookie).cr(); 395 380 } … … 422 407 foreach (HeaderElement header; headers) 423 408 if (header.name.value == HttpHeader.Cookie.value) 424 { 425 buffer.setValidContent (header.value); 426 parser.next (buffer, stack); 427 } 409 parser.parse (header.value); 428 410 } 429 411 return stack; … … 456 438 { 457 439 this.headers = headers; 458 writer = new HttpWriter (headers.getOutputBuffer ());440 writer = new HttpWriter (headers.getOutputBuffer); 459 441 } 460 442 … … 486 468 *******************************************************************************/ 487 469 488 class CookieParser : Scanner470 class CookieParser : IteratorT!(char) 489 471 { 490 472 private enum State {Begin, LValue, Equals, RValue, Token, SQuote, DQuote}; 491 473 474 private CookieStack stack; 475 476 /*********************************************************************** 477 478 ***********************************************************************/ 479 480 this (CookieStack stack) 481 { 482 super (); 483 this.stack = stack; 484 } 485 486 /*********************************************************************** 487 488 Callback for iterator.next(). We scan for name-value 489 pairs, populating Cookie instances along the way. 490 491 ***********************************************************************/ 492 493 protected uint scan (void[] data) 494 { 495 char c; 496 int mark, 497 vrsn; 498 char[] name, 499 token; 500 Cookie cookie; 501 502 State state = State.Begin; 503 char[] content = cast(char[]) data; 504 505 /*************************************************************** 506 507 Found a value; set that also 508 509 ***************************************************************/ 510 511 void setValue (int i) 512 { 513 token = content [mark..i]; 514 //Print ("::name '%.*s'\n", name); 515 //Print ("::value '%.*s'\n", token); 516 517 if (name[0] != '$') 518 { 519 cookie = stack.push(); 520 cookie.setName (name); 521 cookie.setValue (token); 522 cookie.setVersion (vrsn); 523 } 524 else 525 switch (toLower (name)) 526 { 527 case "$path": 528 if (cookie) 529 cookie.setPath (token); 530 break; 531 532 case "$domain": 533 if (cookie) 534 cookie.setDomain (token); 535 break; 536 537 case "$version": 538 vrsn = cast(int) Integer.parse (token); 539 break; 540 541 default: 542 break; 543 } 544 state = State.Begin; 545 } 546 547 /*************************************************************** 548 549 Scan content looking for cookie fields 550 551 ***************************************************************/ 552 553 for (int i; i < content.length; ++i) 554 { 555 c = content [i]; 556 switch (state) 557 { 558 // look for an lValue 559 case State.Begin: 560 mark = i; 561 if (isalpha (c) || c is '$') 562 state = State.LValue; 563 continue; 564 565 // scan until we have all lValue chars 566 case State.LValue: 567 if (! isalnum (c)) 568 { 569 state = State.Equals; 570 name = content [mark..i]; 571 --i; 572 } 573 continue; 574 575 // should now have either a '=', ';', or ',' 576 case State.Equals: 577 if (c is '=') 578 state = State.RValue; 579 else 580 if (c is ',' || c is ';') 581 // get next NVPair 582 state = State.Begin; 583 continue; 584 585 // look for a quoted token, or a plain one 586 case State.RValue: 587 mark = i; 588 if (c is '\'') 589 state = State.SQuote; 590 else 591 if (c is '"') 592 state = State.DQuote; 593 else 594 if (isalpha (c)) 595 state = State.Token; 596 continue; 597 598 // scan for all plain token chars 599 case State.Token: 600 if (! isalnum (c)) 601 { 602 setValue (i); 603 --i; 604 } 605 continue; 606 607 // scan until the next ' 608 case State.SQuote: 609 if (c is '\'') 610 ++mark, setValue (i); 611 continue; 612 613 // scan until the next " 614 case State.DQuote: 615 if (c is '"') 616 ++mark, setValue (i); 617 continue; 618 619 default: 620 continue; 621 } 622 } 623 624 // we ran out of content; patch partial cookie values 625 if (state is State.Token) 626 setValue (content.length); 627 628 // go home 629 return IConduit.Eof; 630 } 631 492 632 /*********************************************************************** 493 633 … … 508 648 ***********************************************************************/ 509 649 510 bool next (IBuffer buffer, CookieStack stack) 511 { 512 /*************************************************************** 513 514 callback from Scanner.next(). We scan for name-value 515 pairs, populating Cookie instances along the way. 516 517 ***************************************************************/ 518 519 uint scan (char[] content) 520 { 521 char c; 522 int mark, 523 vrsn; 524 char[] name, 525 token; 526 Cookie cookie; 527 State state = State.Begin; 528 529 /******************************************************* 530 531 Found a value; set that also 532 533 *******************************************************/ 534 535 void setValue (int i) 536 { 537 token = content [mark..i]; 538 //printf ("::name '%.*s'\n", name); 539 //printf ("::value '%.*s'\n", token); 540 541 if (name[0] != '$') 542 { 543 cookie = stack.push(); 544 cookie.setName (name); 545 cookie.setValue (token); 546 cookie.setVersion (vrsn); 547 } 548 else 549 switch (toLower (name)) 550 { 551 case "$path": 552 if (cookie) 553 cookie.setPath (token); 554 break; 555 556 case "$domain": 557 if (cookie) 558 cookie.setDomain (token); 559 break; 560 561 case "$version": 562 vrsn = cast(int) Integer.parse (token); 563 break; 564 565 default: 566 break; 567 } 568 state = State.Begin; 569 } 570 571 /******************************************************* 572 573 Scan content looking for cookie fields 574 575 *******************************************************/ 576 577 for (int i; i < content.length; ++i) 578 { 579 c = content [i]; 580 switch (state) 581 { 582 // look for an lValue 583 case State.Begin: 584 mark = i; 585 if (isalpha (c) || c == '$') 586 state = State.LValue; 587 continue; 588 589 // scan until we have all lValue chars 590 case State.LValue: 591 if (! isalnum (c)) 592 { 593 state = State.Equals; 594 name = content [mark..i]; 595 --i; 596 } 597 continue; 598 599 // should now have either a '=', ';', or ',' 600 case State.Equals: 601 if (c == '=') 602 state = State.RValue; 603 else 604 if (c == ',' || c == ';') 605 // get next NVPair 606 state = State.Begin; 607 continue; 608 609 // look for a quoted token, or a plain one 610 case State.RValue: 611 mark = i; 612 if (c == '\'') 613 state = State.SQuote; 614 else 615 if (c == '"') 616 state = State.DQuote; 617 else 618 if (isalpha (c)) 619 state = State.Token; 620 continue; 621 622 // scan for all plain token chars 623 case State.Token: 624 if (! isalnum (c)) 625 { 626 setValue (i); 627 --i; 628 } 629 continue; 630 631 // scan until the next ' 632 case State.SQuote: 633 if (c == '\'') 634 ++mark, setValue (i); 635 continue; 636 637 // scan until the next " 638 case State.DQuote: 639 if (c == '"') 640 ++mark, setValue (i); 641 continue; 642 643 default: 644 continue; 645 } 646 } 647 648 // we ran out of content; patch partial cookie values 649 if (state == State.Token) 650 setValue (content.length); 651 652 // go home 653 return IConduit.Eof; 654 } 655 656 return super.next (buffer, &scan); 657 } 658 650 bool parse (char[] header) 651 { 652 super.set (header); 653 return next (); 654 } 659 655 660 656 /********************************************************************** trunk/mango/http/server/HttpHeaders.d
r609 r753 39 39 module mango.http.server.HttpHeaders; 40 40 41 private import mango.io.Token, 42 mango.io.Tokenizer; 41 private import mango.text.LineIterator; 43 42 44 43 private import mango.io.model.IBuffer, … … 153 152 class HttpHeaders : HttpTokens 154 153 { 155 private static BoundToken line;156 157 154 // tell compiler to used super.parse() also 158 155 alias HttpTokens.parse parse; 159 156 160 /********************************************************************** 161 162 Setup a line tokenizer for later use 163 164 **********************************************************************/ 165 166 static this () 167 { 168 // have to make our own LineTokenizer since we can't 169 // depend upon the static Tokenizer.line to be 'live' 170 // before we're invoked here. 171 line = new BoundToken (new LineTokenizer()); 172 } 157 private LineIterator line; 173 158 174 159 /********************************************************************** … … 184 169 // part of the name whilst iterating 185 170 super (':', true); 171 172 // construct a line tokenizer for later usage 173 line = new LineIterator; 186 174 } 187 175 … … 218 206 { 219 207 setParsed (true); 220 while (line.next(input) && line.getLength()) 221 stack.push(line); 208 line.set (input); 209 210 while (line.next && line.get.length) 211 stack.push (line.get); 222 212 } 223 213 trunk/mango/http/server/HttpParams.d
r609 r753 39 39 module mango.http.server.HttpParams; 40 40 41 private import mango.io.Token, 42 mango.io.Tokenizer; 41 private import mango.io.model.IBuffer; 43 42 44 private import mango. io.model.IBuffer;43 private import mango.text.SimpleIterator; 45 44 46 45 private import mango.http.server.HttpTokens; … … 61 60 class HttpParams : HttpTokens 62 61 { 63 private static BoundToken amp;64 65 62 // tell compiler to used super.parse() also 66 63 alias HttpTokens.parse parse; 67 64 68 /********************************************************************** 69 70 Setup a token for extracting each query construct 71 72 **********************************************************************/ 73 74 static this () 75 { 76 amp = new BoundToken (new SimpleTokenizer('&')); 77 } 65 private SimpleIterator amp; 78 66 79 67 /********************************************************************** … … 87 75 { 88 76 super ('='); 77 78 // construct a line tokenizer for later usage 79 amp = new SimpleIterator ("&"); 89 80 } 90 81 … … 121 112 { 122 113 setParsed (true); 123 while (amp.next(input) || amp.getLength()) 124 stack.push (amp); 114 amp.set (input); 115 116 while (amp.next || amp.get.length) 117 stack.push (amp.get); 125 118 } 126 119 } trunk/mango/http/server/HttpRequest.d
r726 r753 39 39 module mango.http.server.HttpRequest; 40 40 41 private import mango.text.Text; 41 private import mango.text.Text, 42 mango.text.LineIterator; 42 43 43 44 private import mango.convert.Atoi; 44 45 45 46 private import mango.io.Uri, 46 mango.io.Token,47 47 mango.io.Buffer, 48 48 mango.io.Reader, 49 49 mango.io.Socket, 50 mango.io.Exception, 51 mango.io.Tokenizer; 50 mango.io.Exception; 52 51 53 52 private import mango.io.model.IBuffer, … … 82 81 // these are per-thread instances also 83 82 private MutableUri uri; 84 private CompositeTokenline;83 private LineIterator line; 85 84 private HttpReader reader; 86 85 private HttpQueryParams params; 87 86 private HttpCookies cookies; 88 87 private StartLine startLine; 89 88 90 89 static private InvalidStateException InvalidState; 91 90 … … 112 111 this (IProviderBridge bridge) 113 112 { 114 IBuffer buffer;115 116 113 super (bridge, null); 117 buffer = super.getBuffer();118 114 119 115 // workspace for parsing the request URI 120 uri = new MutableUri ();116 uri = new MutableUri; 121 117 122 118 // HTTP request start-line (e.g. "GET / HTTP/1.1") 123 startLine = new StartLine ();119 startLine = new StartLine; 124 120 125 121 // input parameters, parsed from the query string 126 params = new HttpQueryParams ();122 params = new HttpQueryParams; 127 123 128 124 // Convenience reader. Typically used for POST requests 129 reader = new HttpReader (buffer); 125 reader = new HttpReader (super.getBuffer); 126 127 // construct a line tokenizer 128 line = new LineIterator; 130 129 131 130 // Cookie parser. This is a wrapper around the Headers 132 cookies = new HttpCookies (getHeader()); 133 134 // Token for initial parsing of input header lines 135 line = new CompositeToken (Tokenizers.line, buffer); 131 cookies = new HttpCookies (getHeader); 136 132 } 137 133 … … 177 173 if (! uried) 178 174 { 179 uri.parse (startLine.getPath ());175 uri.parse (startLine.getPath); 180 176 if (uri.getScheme() is null) 181 uri.setScheme (getServerScheme ());177 uri.setScheme (getServerScheme); 182 178 uried = true; 183 179 } … … 251 247 { 252 248 // parse Query or Post parameters 253 if (! params.isParsed ())249 if (! params.isParsed) 254 250 { 255 char[] query = getRequestUri ().getQuery();251 char[] query = getRequestUri.getQuery(); 256 252 257 253 // do we have a query string? … … 321 317 { 322 318 IBuffer input = super.getBuffer(); 319 line.set (input); 323 320 324 321 // skip any blank lines 325 while (line.next () && line.getLength() ==0)322 while (line.next && line.get.length is 0) 326 323 {} 327 324 … … 331 328 332 329 // load HTTP request 333 startLine.parse (line. toString());330 startLine.parse (line.get); 334 331 335 332 // populate headers trunk/mango/http/server/HttpTokens.d
r692 r753 41 41 private import mango.text.Text; 42 42 43 private import mango.io.Token, 44 mango.io.Buffer, 45 mango.io.Tokenizer; 43 private import mango.io.Buffer; 46 44 47 45 private import mango.convert.Integer, trunk/mango/http/utils/TokenStack.d
r609 r753 39 39 module mango.http.utils.TokenStack; 40 40 41 private import mango.io.Token, 42 mango.io.Exception; 41 private import mango.io.Exception; 43 42 44 43 /****************************************************************************** … … 58 57 extern (C) int strncasecmp (char *, char*, uint); 59 58 } 59 60 61 /****************************************************************************** 62 63 Internal representation of a token 64 65 ******************************************************************************/ 66 67 class Token 68 { 69 private char[] value; 70 71 Token set (char[] value) 72 { 73 this.value = value; 74 return this; 75 } 76 77 char[] toString () 78 { 79 return value; 80 } 81 } 60 82 61 83 /****************************************************************************** … … 163 185 164 186 final int size () 165 { 187 { 166 188 return depth; 167 189 } … … 176 198 final Token push (char[] content) 177 199 { 178 return push().set (content);200 return push().set (content); 179 201 } 180 202 … … 188 210 final Token push (Token token) 189 211 { 190 return push (token.toString());212 return push (token.toString()); 191 213 } 192 214 trunk/mango/io/Buffer.d
r745 r753 236 236 this (IConduit conduit) 237 237 { 238 this (conduit.bufferSize ());238 this (conduit.bufferSize); 239 239 setConduit (conduit); 240 this.style = conduit.isTextual ? Text : Binary; 240 241 } 241 242 … … 344 345 return this; 345 346 } 346 /+ 347 /*********************************************************************** 348 349 Overridable method to grow the buffer to the specified size 350 when it becomes full. Default is to not grow at all. 351 352 ***********************************************************************/ 353 354 protected bool grow (uint size) 355 { 356 return false; 357 } 358 +/ 347 359 348 /*********************************************************************** 360 349 … … 442 431 } 443 432 else 444 // try to grow buffer ... 445 // if (! grow (size)) 446 error (overflow); 433 error (overflow); 447 434 448 435 copy (src, size); … … 491 478 /*********************************************************************** 492 479 480 Support for tokenizing iterators. 481 482 <
