1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.jetty.ajp;
16
17 import java.io.IOException;
18 import java.util.HashMap;
19 import java.util.Iterator;
20
21 import org.mortbay.io.Buffer;
22 import org.mortbay.io.Buffers;
23 import org.mortbay.io.ByteArrayBuffer;
24 import org.mortbay.io.EndPoint;
25 import org.mortbay.jetty.*;
26 import org.mortbay.jetty.HttpFields.Field;
27 import org.mortbay.log.Log;
28 import org.mortbay.util.TypeUtil;
29
30
31
32
33
34 public class Ajp13Generator extends AbstractGenerator
35 {
36 private static HashMap __headerHash = new HashMap();
37
38 static
39 {
40 byte[] xA001 =
41 { (byte) 0xA0, (byte) 0x01 };
42 byte[] xA002 =
43 { (byte) 0xA0, (byte) 0x02 };
44 byte[] xA003 =
45 { (byte) 0xA0, (byte) 0x03 };
46 byte[] xA004 =
47 { (byte) 0xA0, (byte) 0x04 };
48 byte[] xA005 =
49 { (byte) 0xA0, (byte) 0x05 };
50 byte[] xA006 =
51 { (byte) 0xA0, (byte) 0x06 };
52 byte[] xA007 =
53 { (byte) 0xA0, (byte) 0x07 };
54 byte[] xA008 =
55 { (byte) 0xA0, (byte) 0x08 };
56 byte[] xA009 =
57 { (byte) 0xA0, (byte) 0x09 };
58 byte[] xA00A =
59 { (byte) 0xA0, (byte) 0x0A };
60 byte[] xA00B =
61 { (byte) 0xA0, (byte) 0x0B };
62 __headerHash.put("Content-Type", xA001);
63 __headerHash.put("Content-Language", xA002);
64 __headerHash.put("Content-Length", xA003);
65 __headerHash.put("Date", xA004);
66 __headerHash.put("Last-Modified", xA005);
67 __headerHash.put("Location", xA006);
68 __headerHash.put("Set-Cookie", xA007);
69 __headerHash.put("Set-Cookie2", xA008);
70 __headerHash.put("Servlet-Engine", xA009);
71 __headerHash.put("Status", xA00A);
72 __headerHash.put("WWW-Authenticate", xA00B);
73
74 }
75
76
77
78
79 private static final byte[] AJP13_CPONG_RESPONSE =
80 { 'A', 'B', 0, 1, 9};
81
82 private static final byte[] AJP13_END_RESPONSE =
83 { 'A', 'B', 0, 2, 5, 1 };
84
85
86
87
88
89 private static final byte[] AJP13_MORE_CONTENT =
90 { 'A', 'B', 0, 3, 6, 31, -7 };
91
92 private static String SERVER = "Server: Jetty(6.0.x)";
93
94 public static void setServerVersion(String version)
95 {
96 SERVER = "Jetty(" + version + ")";
97 }
98
99
100 private boolean _expectMore = false;
101
102 private boolean _needMore = false;
103
104 private boolean _needEOC = false;
105
106 private boolean _bufferPrepared = false;
107
108
109 public Ajp13Generator(Buffers buffers, EndPoint io, int headerBufferSize, int contentBufferSize)
110 {
111 super(buffers, io, headerBufferSize, contentBufferSize);
112 }
113
114
115 public void reset(boolean returnBuffers)
116 {
117 super.reset(returnBuffers);
118
119 _needEOC = false;
120 _needMore = false;
121 _expectMore = false;
122 _bufferPrepared = false;
123 _last=false;
124
125
126
127 _state = STATE_HEADER;
128
129 _status = 0;
130 _version = HttpVersions.HTTP_1_1_ORDINAL;
131 _reason = null;
132 _method = null;
133 _uri = null;
134
135 _contentWritten = 0;
136 _contentLength = HttpTokens.UNKNOWN_CONTENT;
137 _last = false;
138 _head = false;
139 _noContent = false;
140 _close = false;
141
142
143
144
145 _header = null;
146 _buffer = null;
147 _content = null;
148
149
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167 public void addContent(Buffer content, boolean last) throws IOException
168 {
169 if (_noContent)
170 {
171 content.clear();
172 return;
173 }
174
175 if (content.isImmutable())
176 throw new IllegalArgumentException("immutable");
177
178 if (_last || _state == STATE_END)
179 {
180 Log.debug("Ignoring extra content {}", content);
181 content.clear();
182 return;
183 }
184 _last = last;
185
186 if(!_endp.isOpen())
187 {
188 _state = STATE_END;
189 return;
190 }
191
192
193 if (_content != null && _content.length() > 0)
194 {
195
196 flush();
197 if (_content != null && _content.length() > 0)
198 throw new IllegalStateException("FULL");
199 }
200
201 _content = content;
202
203 _contentWritten += content.length();
204
205
206 if (_head)
207 {
208
209 content.clear();
210 _content = null;
211 }
212 else
213 {
214
215 initContent();
216
217 int len = 0;
218 len = _buffer.put(_content);
219
220
221 if (len > 0 && _buffer.space() == 0)
222 {
223 len--;
224 _buffer.setPutIndex(_buffer.putIndex() - 1);
225 }
226
227 _content.skip(len);
228
229 if (_content.length() == 0)
230 _content = null;
231 }
232 }
233
234
235
236
237
238
239
240
241
242
243 public boolean addContent(byte b) throws IOException
244 {
245
246 if (_noContent)
247 return false;
248
249 if (_last || _state == STATE_END)
250 throw new IllegalStateException("Closed");
251
252
253 if(!_endp.isOpen())
254 {
255 _state = STATE_END;
256 return false;
257 }
258
259
260 if (_content != null && _content.length() > 0)
261 {
262 flush();
263 if (_content != null && _content.length() > 0)
264 throw new IllegalStateException("FULL");
265 }
266
267 _contentWritten++;
268
269
270 if (_head)
271 return false;
272
273
274 initContent();
275
276
277
278 _buffer.put(b);
279
280 return _buffer.space() <= 1;
281 }
282
283
284
285
286
287
288
289
290
291 protected int prepareUncheckedAddContent() throws IOException
292 {
293 if (_noContent)
294 return -1;
295
296 if (_last || _state == STATE_END)
297 throw new IllegalStateException("Closed");
298
299
300 if(!_endp.isOpen())
301 {
302 _state = STATE_END;
303 return -1;
304 }
305
306
307 Buffer content = _content;
308 if (content != null && content.length() > 0)
309 {
310 flush();
311 if (content != null && content.length() > 0)
312 throw new IllegalStateException("FULL");
313 }
314
315
316 initContent();
317
318 _contentWritten -= _buffer.length();
319
320
321 if (_head)
322 return Integer.MAX_VALUE;
323
324 return _buffer.space() - 1;
325 }
326
327
328 public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
329 {
330 if (_state != STATE_HEADER)
331 return;
332
333 if (_last && !allContentAdded)
334 throw new IllegalStateException("last?");
335 _last = _last | allContentAdded;
336
337 boolean has_server = false;
338 if (_version == HttpVersions.HTTP_1_0_ORDINAL)
339 _close = true;
340
341
342 if (_header == null)
343 _header = _buffers.getBuffer(_headerBufferSize);
344
345 Buffer tmpbuf = _buffer;
346 _buffer = _header;
347
348 try
349 {
350
351 _buffer.put((byte) 'A');
352 _buffer.put((byte) 'B');
353 addInt(0);
354 _buffer.put((byte) 0x4);
355 addInt(_status);
356 if (_reason == null)
357 _reason = getReasonBuffer(_status);
358 if (_reason == null)
359 _reason = new ByteArrayBuffer(TypeUtil.toString(_status));
360 addBuffer(_reason);
361
362 if (_status == 100 || _status == 204 || _status == 304)
363 {
364 _noContent = true;
365 _content = null;
366 }
367
368
369
370 int field_index = _buffer.putIndex();
371 addInt(0);
372
373 int num_fields = 0;
374
375 if (fields != null)
376 {
377
378 Iterator i = fields.getFields();
379
380 while (i.hasNext())
381 {
382 num_fields++;
383 Field f = (Field) i.next();
384
385 byte[] codes = (byte[]) __headerHash.get(f.getName());
386 if (codes != null)
387 {
388 _buffer.put(codes);
389 }
390 else
391 {
392 addString(f.getName());
393 }
394 addString(f.getValue());
395 }
396 }
397
398 if (!has_server && _status > 100 && getSendServerVersion())
399 {
400 num_fields++;
401 addString("Server");
402 addString(SERVER);
403 }
404
405
406
407
408 int tmp = _buffer.putIndex();
409 _buffer.setPutIndex(field_index);
410 addInt(num_fields);
411 _buffer.setPutIndex(tmp);
412
413
414
415
416 int payloadSize = _buffer.length() - 4;
417
418
419
420 addInt(2, payloadSize);
421 }
422 finally
423 {
424 _buffer = tmpbuf;
425 }
426
427
428 _state = STATE_CONTENT;
429
430 }
431
432
433
434
435
436
437
438 public void complete() throws IOException
439 {
440 if (_state == STATE_END)
441 return;
442
443 super.complete();
444
445 if (_state < STATE_FLUSHING)
446 {
447 _state = STATE_FLUSHING;
448 _needEOC = true;
449 }
450
451 flush();
452 }
453
454
455 public long flush() throws IOException
456 {
457 try
458 {
459 if (_state == STATE_HEADER && !_expectMore)
460 throw new IllegalStateException("State==HEADER");
461 prepareBuffers();
462
463 if (_endp == null)
464 {
465
466
467
468
469
470
471 if (!_expectMore && _needEOC && _buffer != null)
472 {
473 _buffer.put(AJP13_END_RESPONSE);
474 }
475 _needEOC = false;
476 return 0;
477 }
478
479
480
481 int total = 0;
482 long last_len = -1;
483 Flushing: while (true)
484 {
485 int len = -1;
486 int to_flush = ((_header != null && _header.length() > 0) ? 4 : 0) | ((_buffer != null && _buffer.length() > 0) ? 2 : 0);
487
488
489 switch (to_flush)
490 {
491 case 7:
492 throw new IllegalStateException();
493
494
495 case 6:
496 len = _endp.flush(_header, _buffer, null);
497
498 break;
499 case 5:
500 throw new IllegalStateException();
501
502
503 case 4:
504 len = _endp.flush(_header);
505 break;
506 case 3:
507 throw new IllegalStateException();
508
509
510 case 2:
511 len = _endp.flush(_buffer);
512
513 break;
514 case 1:
515 throw new IllegalStateException();
516
517
518 case 0:
519 {
520
521 if (_header != null)
522 _header.clear();
523
524 _bufferPrepared = false;
525
526 if (_buffer != null)
527 {
528 _buffer.clear();
529
530
531
532 _buffer.setPutIndex(7);
533 _buffer.setGetIndex(7);
534
535
536
537
538
539 if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
540 {
541
542 _buffer.put(_content);
543 _content.clear();
544 _content = null;
545 break Flushing;
546 }
547
548 }
549
550
551
552
553 if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
554 {
555 if (_state == STATE_FLUSHING)
556 _state = STATE_END;
557
558
559
560
561
562
563
564 break Flushing;
565 }
566
567
568 prepareBuffers();
569 }
570 }
571
572
573
574 if (len <= 0)
575 {
576 if (last_len <= 0)
577 break Flushing;
578 break;
579 }
580 last_len = len;
581 total += len;
582 }
583
584
585
586 return total;
587 }
588 catch (IOException e)
589 {
590 Log.ignore(e);
591 throw (e instanceof EofException) ? e : new EofException(e);
592 }
593
594 }
595
596
597 private void prepareBuffers()
598 {
599 if (!_bufferPrepared)
600 {
601
602
603 if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
604 {
605
606 int len = _buffer.put(_content);
607
608
609 if (len > 0 && _buffer.space() == 0)
610 {
611 len--;
612 _buffer.setPutIndex(_buffer.putIndex() - 1);
613 }
614 _content.skip(len);
615
616 if (_content.length() == 0)
617 _content = null;
618
619 if (_buffer.length() == 0)
620 {
621 _content = null;
622 }
623 }
624
625
626 if (_buffer != null)
627 {
628
629 int payloadSize = _buffer.length();
630
631
632
633
634
635
636 if (payloadSize > 0)
637 {
638 _bufferPrepared = true;
639
640 _buffer.put((byte) 0);
641 int put = _buffer.putIndex();
642 _buffer.setGetIndex(0);
643 _buffer.setPutIndex(0);
644 _buffer.put((byte) 'A');
645 _buffer.put((byte) 'B');
646 addInt(payloadSize + 4);
647 _buffer.put((byte) 3);
648 addInt(payloadSize);
649 _buffer.setPutIndex(put);
650 }
651 }
652
653 if (_needMore)
654 {
655
656 if (_header == null)
657 {
658 _header = _buffers.getBuffer(_headerBufferSize);
659 }
660
661 if (_buffer == null && _header != null && _header.space() >= AJP13_MORE_CONTENT.length)
662 {
663 _header.put(AJP13_MORE_CONTENT);
664 _needMore = false;
665 }
666 else if (_buffer != null && _buffer.space() >= AJP13_MORE_CONTENT.length)
667 {
668
669
670 _buffer.put(AJP13_MORE_CONTENT);
671 _needMore = false;
672 _bufferPrepared = true;
673 }
674
675 }
676
677 if (!_expectMore && _needEOC)
678 {
679 if (_buffer == null && _header.space() >= AJP13_END_RESPONSE.length)
680 {
681
682 _header.put(AJP13_END_RESPONSE);
683 _needEOC = false;
684 }
685 else if (_buffer != null && _buffer.space() >= AJP13_END_RESPONSE.length)
686 {
687
688
689
690 _buffer.put(AJP13_END_RESPONSE);
691 _needEOC = false;
692 _bufferPrepared = true;
693 }
694 }
695 }
696 }
697
698
699 public boolean isComplete()
700 {
701 return !_expectMore && _state == STATE_END;
702 }
703
704
705 private void initContent() throws IOException
706 {
707 if (_buffer == null)
708 {
709 _buffer = _buffers.getBuffer(_contentBufferSize);
710 _buffer.setPutIndex(7);
711 _buffer.setGetIndex(7);
712 }
713 }
714
715
716 private void addInt(int i)
717 {
718 _buffer.put((byte) ((i >> 8) & 0xFF));
719 _buffer.put((byte) (i & 0xFF));
720 }
721
722
723 private void addInt(int startIndex, int i)
724 {
725 _buffer.poke(startIndex, (byte) ((i >> 8) & 0xFF));
726 _buffer.poke((startIndex + 1), (byte) (i & 0xFF));
727 }
728
729
730 private void addString(String str)
731 {
732 if (str == null)
733 {
734 addInt(0xFFFF);
735 return;
736 }
737
738
739
740 byte[] b = str.getBytes();
741
742 addInt(b.length);
743
744 _buffer.put(b);
745 _buffer.put((byte) 0);
746 }
747
748
749 private void addBuffer(Buffer b)
750 {
751 if (b == null)
752 {
753 addInt(0xFFFF);
754 return;
755 }
756
757 addInt(b.length());
758 _buffer.put(b);
759 _buffer.put((byte) 0);
760 }
761
762
763 public void getBodyChunk() throws IOException
764 {
765 _needMore = true;
766 _expectMore = true;
767 flush();
768 }
769
770
771 public void gotBody()
772 {
773 _needMore = false;
774 _expectMore = false;
775 }
776
777
778
779 public void sendCPong() throws IOException
780 {
781
782 Buffer buff = _buffers.getBuffer(AJP13_CPONG_RESPONSE.length);
783 buff.put(AJP13_CPONG_RESPONSE);
784
785
786 do
787 {
788 _endp.flush(buff);
789
790 }
791 while(buff.length() >0);
792 _buffers.returnBuffer(buff);
793
794 reset(true);
795
796 }
797
798
799
800 }