1 | // Licensed to the Apache Software Foundation (ASF) under one |
2 | // or more contributor license agreements. See the NOTICE file |
3 | // distributed with this work for additional information |
4 | // regarding copyright ownership. The ASF licenses this file |
5 | // to you under the Apache License, Version 2.0 (the |
6 | // "License"); you may not use this file except in compliance |
7 | // with the License. You may obtain a copy of the License at |
8 | // |
9 | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | // |
11 | // Unless required by applicable law or agreed to in writing, |
12 | // software distributed under the License is distributed on an |
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | // KIND, either express or implied. See the License for the |
15 | // specific language governing permissions and limitations |
16 | // under the License. |
17 | |
18 | |
19 | #ifndef BRPC_PROGRESSIVE_READER_H |
20 | #define BRPC_PROGRESSIVE_READER_H |
21 | |
22 | #include "brpc/shared_object.h" |
23 | |
24 | |
25 | namespace brpc { |
26 | |
27 | // [Implement by user] |
28 | // To read a very long or infinitely long response progressively. |
29 | // Client-side usage: |
30 | // cntl.response_will_be_read_progressively(); // before RPC |
31 | // ... |
32 | // channel.CallMethod(NULL, &cntl, NULL, NULL, NULL/*done*/); |
33 | // ... |
34 | // cntl.ReadProgressiveAttachmentBy(new MyProgressiveReader); // after RPC |
35 | // ... |
36 | class ProgressiveReader { |
37 | public: |
38 | // Called when one part was read. |
39 | // Error returned is treated as *permenant* and the socket where the |
40 | // data was read will be closed. |
41 | // A temporary error may be handled by blocking this function, which |
42 | // may block the HTTP parsing on the socket. |
43 | virtual butil::Status OnReadOnePart(const void* data, size_t length) = 0; |
44 | |
45 | // Called when there's nothing to read anymore. The `status' is a hint for |
46 | // why this method is called. |
47 | // - status.ok(): the message is complete and successfully consumed. |
48 | // - otherwise: socket was broken or OnReadOnePart() failed. |
49 | // This method will be called once and only once. No other methods will |
50 | // be called after. User can release the memory of this object inside. |
51 | virtual void OnEndOfMessage(const butil::Status& status) = 0; |
52 | |
53 | protected: |
54 | virtual ~ProgressiveReader() {} |
55 | }; |
56 | |
57 | // [Implement by protocol handlers] |
58 | // Share ProgressiveReader between protocol handlers and controllers. |
59 | // Take chunked HTTP response as an example: |
60 | // 1. The protocol handler parses headers and goes to ProcessHttpResponse |
61 | // before reading all body. |
62 | // 2. ProcessHttpResponse sets controller's RPA which is just the HttpContext |
63 | // in this case. The RPC ends at the end of ProcessHttpResponse. |
64 | // 3. When the RPC ends, user may call Controller.ReadProgressiveAttachmentBy() |
65 | // to read the body. If user does not set a reader, controller sets one |
66 | // ignoring all bytes read before self's destruction. |
67 | // The call chain: |
68 | // Controller.ReadProgressiveAttachmentBy() |
69 | // -> ReadableProgressiveAttachment.ReadProgressiveAttachmentBy() |
70 | // -> HttpMesage.SetBodyReader() |
71 | // -> ProgressiveReader.OnReadOnePart() |
72 | // Already-read body will be fed immediately and the reader is remembered. |
73 | // 4. The protocol handler also sets a reference to the RPA in the socket. |
74 | // When new part arrives, HttpMessage.on_body is called, which calls |
75 | // ProgressiveReader.OnReadOnePart() when reader is set. |
76 | // 5. When all body is read, the socket releases the reference to the RPA. |
77 | // If controller is deleted after all body is read, the RPA should be |
78 | // destroyed at controller's deletion. If controller is deleted before |
79 | // all body is read, the RPA should be destroyed when all body is read |
80 | // or the socket is destroyed. |
81 | class ReadableProgressiveAttachment : public SharedObject { |
82 | public: |
83 | // Read the constantly-appending attachment by a ProgressiveReader. |
84 | // Any error occurred should destroy the reader by calling r->Destroy(). |
85 | // r->Destroy() should be guaranteed to be called once and only once. |
86 | virtual void ReadProgressiveAttachmentBy(ProgressiveReader* r) = 0; |
87 | }; |
88 | |
89 | } // namespace brpc |
90 | |
91 | |
92 | #endif // BRPC_PROGRESSIVE_READER_H |
93 | |