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