1 /**
2  * Tests
3  * 
4  * Copyright:
5  * (C) 2012-2015 Tatsuhiro Tsujikawa
6  * (C) 2014-2015 Etienne Cimon
7  *
8  * License: 
9  * Distributed under the terms of the MIT license with an additional section 1.2 of the curl/libcurl project. 
10  * Consult the provided LICENSE.md file for details
11  */
12 module libhttp2.tests;
13 
14 import std.c.stdlib;
15 import std.c.string;
16 import libhttp2.constants;
17 import libhttp2.types;
18 import libhttp2.helpers;
19 import libhttp2.inflater;
20 import libhttp2.deflater;
21 import libhttp2.session;
22 import libhttp2.stream;
23 import libhttp2.frame;
24 import libhttp2.huffman;
25 import libhttp2.buffers;
26 
27 struct HeaderFields
28 {
29 	HeaderField[] opSlice() 
30 	{
31 		return hfa_raw[0 .. length];
32 	}
33 
34 	HeaderField[] opSlice(size_t i, size_t j) {
35 		assert(j <= length);
36 		return hfa_raw[i .. j];
37 	}
38 
39 	size_t opDollar() const { return length; }
40 
41 	void add(HeaderField hf) {
42 		HeaderField* hfp = hfa_raw.ptr + length;
43 		length++;
44 		if (hf.name.length > 0) 
45 			hfp.name = Mem.copy(hf.name);
46 		
47 		if (hf.value.length > 0)
48 			hfp.value = Mem.copy(hf.value);
49 
50 		hfp.flag = hf.flag;
51 	}
52 
53 	void reset() {
54 		size_t i;
55 		for (i = 0; i < length; ++i) {
56 			if (hfa_raw[i].name) 
57 				Mem.free(hfa_raw[i].name);
58 			if (hfa_raw[i].value) 
59 				Mem.free(hfa_raw[i].value);
60 		}
61 		hfa_raw.destroy();
62 		length = 0;
63 	}
64 
65 	/// returns the amount of headers added to hfa
66 	int inflate(ref Inflater inflater, Buffers bufs, size_t offset) 
67 	{
68 		int rv;
69 		HeaderField hf;
70 		InflateFlag inflate_flag;
71 		Buffers.Chain ci;
72 		Buffer* buf;
73 		Buffer bp;
74 		bool is_final;
75 		int processed;
76 		
77 		for (ci = bufs.head; ci; ci = ci.next) {
78 			buf = &ci.buf;
79 			is_final = buf.length == 0 || !ci.next;
80 			bp = *buf;
81 
82 			if (offset) {
83 				int n;
84 				
85 				n = min(cast(int)offset, bp.length);
86 				bp.pos += n;
87 				offset -= n;
88 			}
89 
90 			for (;;) {
91 				inflate_flag = InflateFlag.NONE;
92 				rv = inflater.inflate(hf, inflate_flag, bp[], is_final);
93 				if (rv < 0)
94 					return rv;
95 				
96 				bp.pos += rv;
97 				processed += rv;
98 				if (inflate_flag & InflateFlag.EMIT) 
99 					add(hf);
100 				if (inflate_flag & InflateFlag.FINAL)
101 					break;
102 			}
103 		}
104 		inflater.endHeaders();
105 		
106 		return processed;
107 	}
108 
109 	HeaderField[256] hfa_raw;
110 	size_t length;
111 }
112 
113 int compareBytes(in string a, in string b) {
114 	int rv;
115 	
116 	if (a.length == b.length) {
117 		return memcmp(a.ptr, b.ptr, a.length);
118 	}
119 	
120 	if (a.length < b.length) {
121 		rv = memcmp(a.ptr, b.ptr, a.length);
122 		
123 		if (rv == 0) {
124 			return -1;
125 		}
126 		
127 		return rv;
128 	}
129 	
130 	rv = memcmp(a.ptr, b.ptr, b.length);
131 	
132 	if (rv == 0) {
133 		return 1;
134 	}
135 	
136 	return rv;
137 }
138 
139 extern(C)
140 int compareHeaderFields(in void *lhs, in void *rhs) {
141 	const HeaderField a = *cast(HeaderField*)lhs;
142 	const HeaderField b = *cast(HeaderField*)rhs;
143 	int rv;
144 	
145 	rv = compareBytes(a.name, b.name);
146 	
147 	if (rv == 0) {
148 		return compareBytes(a.value, b.value);
149 	}
150 	
151 	return rv;
152 }
153 
154 void sort(HeaderField[] hfa) {
155 	qsort(hfa.ptr, hfa.length, HeaderField.sizeof, &compareHeaderFields);
156 }
157 
158 void packHeaders(Buffers bufs, ref Deflater deflater, int stream_id, FrameFlags flags, in HeaderField[] hfa)
159 {
160 	HeaderField[] hfa_copy;
161 	Frame frame;
162 	hfa_copy = hfa.copy();		
163 	frame.headers = Headers(flags, stream_id, HeadersCategory.HEADERS, PrioritySpec.init, hfa_copy);
164 	frame.headers.pack(bufs, deflater);	
165 	frame.headers.free();
166 }
167 
168 void packPushPromise(Buffers bufs, ref Deflater deflater, int stream_id, FrameFlags flags, int promised_stream_id, in HeaderField[] hfa) {
169 	HeaderField[] hfa_copy;
170 	Frame frame;
171 	hfa_copy = hfa.copy();
172 	
173 	frame.push_promise = PushPromise(flags, stream_id, promised_stream_id, hfa_copy);
174 	frame.push_promise.pack(bufs, deflater);
175 	frame.push_promise.free();
176 }
177 
178 Buffers framePackBuffers() 
179 {
180 	/* 1 for Pad Length */
181 	return new Buffers(4096, 16, FRAME_HDLEN + 1);
182 }
183 
184 Buffers largeBuffers(size_t chunk_size) 
185 {
186 	/* 1 for Pad Length */
187 	return new Buffers(chunk_size, 16, FRAME_HDLEN + 1);
188 }
189 
190 private Stream openStreamWithAll(Session session, int stream_id, int weight, bool exclusive, Stream dep_stream)
191 {
192 	PrioritySpec pri_spec;
193 	int dep_stream_id;
194 	
195 	if (dep_stream) {
196 		dep_stream_id = dep_stream.id;
197 	} else {
198 		dep_stream_id = 0;
199 	}
200 	
201 	pri_spec = PrioritySpec(dep_stream_id, weight, exclusive);
202 
203 	return session.openStream(stream_id, StreamFlags.NONE, pri_spec, StreamState.OPENED, null);
204 }
205 
206 Stream openStream(Session session, int stream_id) 
207 {
208 	return openStreamWithAll(session, stream_id, DEFAULT_WEIGHT, false, null);
209 }
210 
211 Stream openStreamWithDep(Session session, int stream_id, Stream dep_stream)
212 {
213 	return openStreamWithAll(session, stream_id, DEFAULT_WEIGHT, false, dep_stream);
214 }
215 
216 Stream openStreamWithDepWeight(Session session, int stream_id, int weight, Stream dep_stream)
217 {
218 	return openStreamWithAll(session, stream_id, weight, false, dep_stream);
219 }
220 
221 Stream openStreamWithDepExclusive(Session session, int stream_id, Stream dep_stream) 
222 {
223 	return openStreamWithAll(session, stream_id, DEFAULT_WEIGHT, true, dep_stream);
224 }
225 
226 OutboundItem createDataOutboundItem() {
227 	return Mem.alloc!OutboundItem();
228 }