Project

General

Profile

fix-2147-in-1.4.x.patch

Fix for 1.4.x (version 2 - fix read_offset calculation) - stbuehler, 2010-01-22 17:47

View differences:

src/base.h
431 431

  
432 432
#ifdef USE_OPENSSL
433 433
	SSL *ssl;
434
	buffer *ssl_error_want_reuse_buffer;
435 434
# ifndef OPENSSL_NO_TLSEXT
436 435
	buffer *tlsext_server_name;
437 436
# endif
src/chunk.c
197 197
int chunkqueue_append_buffer_weak(chunkqueue *cq, buffer *mem) {
198 198
	chunk *c;
199 199

  
200
	if (mem->used == 0) return 0;
201

  
202 200
	c = chunkqueue_get_unused_chunk(cq);
203 201
	c->type = MEM_CHUNK;
204 202
	c->offset = 0;
src/connections.c
192 192

  
193 193
static int connection_handle_read_ssl(server *srv, connection *con) {
194 194
#ifdef USE_OPENSSL
195
	int r, ssl_err, len, count = 0;
195
	int r, ssl_err, len, count = 0, read_offset, toread;
196 196
	buffer *b = NULL;
197 197

  
198 198
	if (!con->conf.is_ssl) return -1;
199 199

  
200
	/* don't resize the buffer if we were in SSL_ERROR_WANT_* */
201

  
202 200
	ERR_clear_error();
203 201
	do {
204
		if (!con->ssl_error_want_reuse_buffer) {
205
			b = buffer_init();
206
			buffer_prepare_copy(b, SSL_pending(con->ssl) + (16 * 1024)); /* the pending bytes + 16kb */
202
		if (NULL != con->read_queue->last)
203
			b = con->read_queue->last->mem;
204

  
205
		if (NULL == b || b->size - b->used < 1024) {
206
			b = chunkqueue_get_append_buffer(con->read_queue);
207
			len = SSL_pending(con->ssl);
208
			if (len < 4*1024) len = 4*1024; /* always alloc >= 4k buffer */
209
			buffer_prepare_copy(b, len + 1);
207 210

  
208 211
			/* overwrite everything with 0 */
209 212
			memset(b->ptr, 0, b->size);
210
		} else {
211
			b = con->ssl_error_want_reuse_buffer;
212 213
		}
213 214

  
214
		len = SSL_read(con->ssl, b->ptr, b->size - 1);
215
		con->ssl_error_want_reuse_buffer = NULL; /* reuse it only once */
215
		read_offset = (b->used > 0) ? b->used - 1 : 0;
216
		toread = b->size - 1 - read_offset;
217

  
218
		len = SSL_read(con->ssl, b->ptr + read_offset, toread);
216 219

  
217 220
		if (len > 0) {
218
			b->used = len;
221
			if (b->used > 0) b->used--;
222
			b->used += len;
219 223
			b->ptr[b->used++] = '\0';
220 224

  
221
		       	/* we move the buffer to the chunk-queue, no need to free it */
225
			con->bytes_read += len;
222 226

  
223
			chunkqueue_append_buffer_weak(con->read_queue, b);
224 227
			count += len;
225
			con->bytes_read += len;
226
			b = NULL;
227 228
		}
228
	} while (len > 0 && count < MAX_READ_LIMIT);
229
	} while (len == toread && count < MAX_READ_LIMIT);
229 230

  
230 231

  
231 232
	if (len < 0) {
......
234 235
		case SSL_ERROR_WANT_READ:
235 236
		case SSL_ERROR_WANT_WRITE:
236 237
			con->is_readable = 0;
237
			con->ssl_error_want_reuse_buffer = b;
238 238

  
239
			b = NULL;
239
			/* the manual says we have to call SSL_read with the same arguments next time.
240
			 * we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway.
241
			 */
240 242

  
241
			/* we have to steal the buffer from the queue-queue */
242 243
			return 0;
243 244
		case SSL_ERROR_SYSCALL:
244 245
			/**
......
297 298

  
298 299
		connection_set_state(srv, con, CON_STATE_ERROR);
299 300

  
300
		buffer_free(b);
301

  
302 301
		return -1;
303 302
	} else if (len == 0) {
304 303
		con->is_readable = 0;
305 304
		/* the other end close the connection -> KEEP-ALIVE */
306 305

  
307
		/* pipelining */
308
		buffer_free(b);
309

  
310 306
		return -2;
311 307
	}
312 308

  
......
321 317
static int connection_handle_read(server *srv, connection *con) {
322 318
	int len;
323 319
	buffer *b;
324
	int toread;
320
	int toread, read_offset;
325 321

  
326 322
	if (con->conf.is_ssl) {
327 323
		return connection_handle_read_ssl(srv, con);
328 324
	}
329 325

  
326
	b = (NULL != con->read_queue->last) ? con->read_queue->last->mem : NULL;
327

  
328
	/* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
329
	 *  us more than 4kb is available
330
	 * if FIONREAD doesn't signal a big chunk we fill the previous buffer
331
	 *  if it has >= 1kb free
332
	 */
330 333
#if defined(__WIN32)
331
	b = chunkqueue_get_append_buffer(con->read_queue);
332
	buffer_prepare_copy(b, 4 * 1024);
333
	len = recv(con->fd, b->ptr, b->size - 1, 0);
334
#else
335
	if (ioctl(con->fd, FIONREAD, &toread) || toread == 0) {
334
	if (NULL == b || b->size - b->used < 1024) {
336 335
		b = chunkqueue_get_append_buffer(con->read_queue);
337 336
		buffer_prepare_copy(b, 4 * 1024);
337
	}
338

  
339
	read_offset = (b->used == 0) ? 0 : b->used - 1;
340
	len = recv(con->fd, b->ptr + read_offset, b->size - 1 - read_offset, 0);
341
#else
342
	if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
343
		if (NULL == b || b->size - b->used < 1024) {
344
			b = chunkqueue_get_append_buffer(con->read_queue);
345
			buffer_prepare_copy(b, 4 * 1024);
346
		}
338 347
	} else {
339 348
		if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
340 349
		b = chunkqueue_get_append_buffer(con->read_queue);
341 350
		buffer_prepare_copy(b, toread + 1);
342 351
	}
343
	len = read(con->fd, b->ptr, b->size - 1);
352

  
353
	read_offset = (b->used == 0) ? 0 : b->used - 1;
354
	len = read(con->fd, b->ptr + read_offset, b->size - 1 - read_offset);
344 355
#endif
345 356

  
346 357
	if (len < 0) {
......
374 385
		con->is_readable = 0;
375 386
	}
376 387

  
377
	b->used = len;
388
	if (b->used > 0) b->used--;
389
	b->used += len;
378 390
	b->ptr[b->used++] = '\0';
379 391

  
380 392
	con->bytes_read += len;
......
850 862
	/* The cond_cache gets reset in response.c */
851 863
	/* config_cond_cache_reset(srv, con); */
852 864

  
853
#ifdef USE_OPENSSL
854
	if (con->ssl_error_want_reuse_buffer) {
855
		buffer_free(con->ssl_error_want_reuse_buffer);
856
		con->ssl_error_want_reuse_buffer = NULL;
857
	}
858
#endif
859

  
860 865
	con->header_len = 0;
861 866
	con->in_error_handler = 0;
862 867

  
......
1128 1133
			} else {
1129 1134
				buffer *b;
1130 1135

  
1131
				b = chunkqueue_get_append_buffer(dst_cq);
1132
				buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
1136
				if (dst_cq->last &&
1137
				    dst_cq->last->type == MEM_CHUNK) {
1138
					b = dst_cq->last->mem;
1139
				} else {
1140
					b = chunkqueue_get_append_buffer(dst_cq);
1141
					/* prepare buffer size for remaining POST data; is < 64kb */
1142
					buffer_prepare_copy(b, con->request.content_length - dst_cq->bytes_in + 1);
1143
				}
1144
				buffer_append_string_len(b, c->mem->ptr + c->offset, toRead);
1133 1145
			}
1134 1146

  
1135 1147
			c->offset += toRead;
1136
-