1 module hunt.http.codec.http.encode.HeadersGenerator; 2 3 import hunt.collection; 4 5 import hunt.http.codec.http.frame.Flags; 6 import hunt.http.codec.http.frame.Frame; 7 import hunt.http.codec.http.frame.FrameType; 8 import hunt.http.codec.http.frame.HeadersFrame; 9 import hunt.http.codec.http.frame.PriorityFrame; 10 import hunt.http.codec.http.hpack.HpackEncoder; 11 import hunt.http.HttpMetaData; 12 13 import hunt.http.codec.http.encode.FrameGenerator; 14 import hunt.http.codec.http.encode.HeaderGenerator; 15 import hunt.http.codec.http.encode.PriorityGenerator; 16 17 import hunt.Exceptions; 18 import std.conv; 19 20 /** 21 */ 22 class HeadersGenerator :FrameGenerator { 23 private HpackEncoder encoder; 24 private int maxHeaderBlockFragment; 25 private PriorityGenerator priorityGenerator; 26 27 this(HeaderGenerator headerGenerator, HpackEncoder encoder) { 28 this(headerGenerator, encoder, 0); 29 } 30 31 this(HeaderGenerator headerGenerator, HpackEncoder encoder, int maxHeaderBlockFragment) { 32 super(headerGenerator); 33 this.encoder = encoder; 34 this.maxHeaderBlockFragment = maxHeaderBlockFragment; 35 this.priorityGenerator = new PriorityGenerator(headerGenerator); 36 } 37 38 override 39 List!(ByteBuffer) generate(Frame frame) { 40 HeadersFrame headersFrame = cast(HeadersFrame) frame; 41 return generateHeaders(headersFrame.getStreamId(), headersFrame.getMetaData(), headersFrame.getPriority(), 42 headersFrame.isEndStream()); 43 } 44 45 List!(ByteBuffer) generateHeaders(int streamId, HttpMetaData metaData, PriorityFrame priority, 46 bool endStream) { 47 List!(ByteBuffer) list = new LinkedList!(ByteBuffer)(); 48 if (streamId < 0) 49 throw new IllegalArgumentException("Invalid stream id: " ~ streamId.to!string()); 50 51 int flags = Flags.NONE; 52 53 if (priority !is null) 54 flags = Flags.PRIORITY; 55 56 int maxFrameSize = getMaxFrameSize(); 57 ByteBuffer hpacked = BufferUtils.allocate(maxFrameSize); 58 BufferUtils.clearToFill(hpacked); 59 encoder.encode(hpacked, metaData); 60 int hpackedLength = hpacked.position(); 61 BufferUtils.flipToFlush(hpacked, 0); 62 63 // Split into CONTINUATION frames if necessary. 64 if (maxHeaderBlockFragment > 0 && hpackedLength > maxHeaderBlockFragment) { 65 if (endStream) 66 flags |= Flags.END_STREAM; 67 68 int length = maxHeaderBlockFragment; 69 if (priority !is null) 70 length += PriorityFrame.PRIORITY_LENGTH; 71 72 ByteBuffer header = generateHeader(FrameType.HEADERS, length, flags, streamId); 73 generatePriority(header, priority); 74 BufferUtils.flipToFlush(header, 0); 75 list.add(header); 76 77 hpacked.limit(maxHeaderBlockFragment); 78 list.add(hpacked.slice()); 79 80 int position = maxHeaderBlockFragment; 81 int limit = position + maxHeaderBlockFragment; 82 while (limit < hpackedLength) { 83 hpacked.position(position).limit(limit); 84 header = generateHeader(FrameType.CONTINUATION, maxHeaderBlockFragment, Flags.NONE, streamId); 85 BufferUtils.flipToFlush(header, 0); 86 list.add(header); 87 list.add(hpacked.slice()); 88 position += maxHeaderBlockFragment; 89 limit += maxHeaderBlockFragment; 90 } 91 92 hpacked.position(position).limit(hpackedLength); 93 header = generateHeader(FrameType.CONTINUATION, hpacked.remaining(), Flags.END_HEADERS, streamId); 94 BufferUtils.flipToFlush(header, 0); 95 list.add(header); 96 list.add(hpacked); 97 } else { 98 flags |= Flags.END_HEADERS; 99 if (endStream) 100 flags |= Flags.END_STREAM; 101 102 int length = hpackedLength; 103 if (priority !is null) 104 length += PriorityFrame.PRIORITY_LENGTH; 105 106 ByteBuffer header = generateHeader(FrameType.HEADERS, length, flags, streamId); 107 generatePriority(header, priority); 108 BufferUtils.flipToFlush(header, 0); 109 list.add(header); 110 list.add(hpacked); 111 } 112 return list; 113 } 114 115 private void generatePriority(ByteBuffer header, PriorityFrame priority) { 116 if (priority !is null) { 117 priorityGenerator.generatePriorityBody(header, priority.getStreamId(), priority.getParentStreamId(), 118 priority.getWeight(), priority.isExclusive()); 119 } 120 } 121 }