| | 544 | |
|---|
| | 545 | class MultipartWrapper(object): |
|---|
| | 546 | r"""Wraps a file-like object, returning '' when Content-Length is reached. |
|---|
| | 547 | |
|---|
| | 548 | The cgi module's logic for reading multipart MIME messages doesn't |
|---|
| | 549 | allow the parts to know when the Content-Length for the entire message |
|---|
| | 550 | has been reached, and doesn't allow for multipart-MIME messages that |
|---|
| | 551 | omit the trailing CRLF (Flash 8's FileReference.upload(url), for example, |
|---|
| | 552 | does this). The read_lines_to_outerboundary function gets stuck in a loop |
|---|
| | 553 | until the socket times out. |
|---|
| | 554 | |
|---|
| | 555 | This rfile wrapper simply monitors the incoming stream. When a read is |
|---|
| | 556 | attempted past the Content-Length, it returns an empty string rather |
|---|
| | 557 | than timing out (of course, if the last read *overlaps* the C-L, you'll |
|---|
| | 558 | get the last bit of data up to C-L, and then the next read will return |
|---|
| | 559 | an empty string). |
|---|
| | 560 | """ |
|---|
| | 561 | |
|---|
| | 562 | def __init__(self, rfile, clen): |
|---|
| | 563 | self.rfile = rfile |
|---|
| | 564 | self.clen = clen |
|---|
| | 565 | self.bytes_read = 0 |
|---|
| | 566 | |
|---|
| | 567 | def read(self, size = None): |
|---|
| | 568 | if self.clen: |
|---|
| | 569 | # Return '' if we've read all the data. |
|---|
| | 570 | if self.bytes_read >= self.clen: |
|---|
| | 571 | return '' |
|---|
| | 572 | |
|---|
| | 573 | # Reduce 'size' if it's over our limit. |
|---|
| | 574 | new_bytes_read = self.bytes_read + size |
|---|
| | 575 | if new_bytes_read > self.clen: |
|---|
| | 576 | size = self.clen - self.bytes_read |
|---|
| | 577 | |
|---|
| | 578 | data = self.rfile.read(size) |
|---|
| | 579 | self.bytes_read += len(data) |
|---|
| | 580 | return data |
|---|
| | 581 | |
|---|
| | 582 | def readline(self, size = None): |
|---|
| | 583 | if size is not None: |
|---|
| | 584 | if self.clen: |
|---|
| | 585 | # Return '' if we've read all the data. |
|---|
| | 586 | if self.bytes_read >= self.clen: |
|---|
| | 587 | return '' |
|---|
| | 588 | |
|---|
| | 589 | # Reduce 'size' if it's over our limit. |
|---|
| | 590 | new_bytes_read = self.bytes_read + size |
|---|
| | 591 | if new_bytes_read > self.clen: |
|---|
| | 592 | size = self.clen - self.bytes_read |
|---|
| | 593 | |
|---|
| | 594 | data = self.rfile.readline(size) |
|---|
| | 595 | self.bytes_read += len(data) |
|---|
| | 596 | return data |
|---|
| | 597 | |
|---|
| | 598 | # User didn't specify a size ... |
|---|
| | 599 | # We read the line in chunks to make sure it's not a 100MB line ! |
|---|
| | 600 | res = [] |
|---|
| | 601 | size = 256 |
|---|
| | 602 | while True: |
|---|
| | 603 | if self.clen: |
|---|
| | 604 | # Return if we've read all the data. |
|---|
| | 605 | if self.bytes_read >= self.clen: |
|---|
| | 606 | return ''.join(res) |
|---|
| | 607 | |
|---|
| | 608 | # Reduce 'size' if it's over our limit. |
|---|
| | 609 | new_bytes_read = self.bytes_read + size |
|---|
| | 610 | if new_bytes_read > self.clen: |
|---|
| | 611 | size = self.clen - self.bytes_read |
|---|
| | 612 | |
|---|
| | 613 | data = self.rfile.readline(size) |
|---|
| | 614 | self.bytes_read += len(data) |
|---|
| | 615 | res.append(data) |
|---|
| | 616 | # See http://www.cherrypy.org/ticket/421 |
|---|
| | 617 | if len(data) < size or data[-1:] == "\n": |
|---|
| | 618 | return ''.join(res) |
|---|
| | 619 | |
|---|
| | 620 | def readlines(self, sizehint = 0): |
|---|
| | 621 | # Shamelessly stolen from StringIO |
|---|
| | 622 | total = 0 |
|---|
| | 623 | lines = [] |
|---|
| | 624 | line = self.readline() |
|---|
| | 625 | while line: |
|---|
| | 626 | lines.append(line) |
|---|
| | 627 | total += len(line) |
|---|
| | 628 | if 0 < sizehint <= total: |
|---|
| | 629 | break |
|---|
| | 630 | line = self.readline() |
|---|
| | 631 | return lines |
|---|
| | 632 | |
|---|
| | 633 | def close(self): |
|---|
| | 634 | self.rfile.close() |
|---|
| | 635 | |
|---|
| | 636 | def __iter__(self): |
|---|
| | 637 | return self.rfile |
|---|
| | 638 | |
|---|
| | 639 | def next(self): |
|---|
| | 640 | if self.clen: |
|---|
| | 641 | # Return '' if we've read all the data. |
|---|
| | 642 | if self.bytes_read >= self.clen: |
|---|
| | 643 | return '' |
|---|
| | 644 | |
|---|
| | 645 | data = self.rfile.next() |
|---|
| | 646 | self.bytes_read += len(data) |
|---|
| | 647 | return data |
|---|
| | 648 | |