001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2009 Sun Microsystems, Inc. 015 * Portions copyright 2011-2013 ForgeRock AS. 016 */ 017 018package org.forgerock.opendj.io; 019 020import static com.forgerock.opendj.ldap.CoreMessages.*; 021 022import java.io.IOException; 023 024import org.forgerock.i18n.LocalizedIllegalArgumentException; 025import org.forgerock.i18n.slf4j.LocalizedLogger; 026import org.forgerock.opendj.ldap.Attribute; 027import org.forgerock.opendj.ldap.AttributeDescription; 028import org.forgerock.opendj.ldap.ByteString; 029import org.forgerock.opendj.ldap.DN; 030import org.forgerock.opendj.ldap.DecodeException; 031import org.forgerock.opendj.ldap.DecodeOptions; 032import org.forgerock.opendj.ldap.DereferenceAliasesPolicy; 033import org.forgerock.opendj.ldap.Entry; 034import org.forgerock.opendj.ldap.Filter; 035import org.forgerock.opendj.ldap.Modification; 036import org.forgerock.opendj.ldap.ModificationType; 037import org.forgerock.opendj.ldap.RDN; 038import org.forgerock.opendj.ldap.ResultCode; 039import org.forgerock.opendj.ldap.SearchScope; 040import org.forgerock.opendj.ldap.controls.Control; 041import org.forgerock.opendj.ldap.controls.GenericControl; 042import org.forgerock.opendj.ldap.requests.AbandonRequest; 043import org.forgerock.opendj.ldap.requests.AddRequest; 044import org.forgerock.opendj.ldap.requests.CompareRequest; 045import org.forgerock.opendj.ldap.requests.DeleteRequest; 046import org.forgerock.opendj.ldap.requests.GenericBindRequest; 047import org.forgerock.opendj.ldap.requests.GenericExtendedRequest; 048import org.forgerock.opendj.ldap.requests.ModifyDNRequest; 049import org.forgerock.opendj.ldap.requests.ModifyRequest; 050import org.forgerock.opendj.ldap.requests.Request; 051import org.forgerock.opendj.ldap.requests.Requests; 052import org.forgerock.opendj.ldap.requests.SearchRequest; 053import org.forgerock.opendj.ldap.requests.UnbindRequest; 054import org.forgerock.opendj.ldap.responses.BindResult; 055import org.forgerock.opendj.ldap.responses.CompareResult; 056import org.forgerock.opendj.ldap.responses.GenericExtendedResult; 057import org.forgerock.opendj.ldap.responses.GenericIntermediateResponse; 058import org.forgerock.opendj.ldap.responses.Response; 059import org.forgerock.opendj.ldap.responses.Responses; 060import org.forgerock.opendj.ldap.responses.Result; 061import org.forgerock.opendj.ldap.responses.SearchResultEntry; 062import org.forgerock.opendj.ldap.responses.SearchResultReference; 063import org.forgerock.opendj.ldap.schema.Schema; 064 065/** 066 * Reads LDAP messages from an underlying ASN.1 reader. 067 * 068 * @param <R> 069 * The type of ASN.1 reader used for decoding elements. 070 */ 071public final class LDAPReader<R extends ASN1Reader> { 072 073 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 074 075 private final DecodeOptions options; 076 private final R reader; 077 078 LDAPReader(final R asn1Reader, final DecodeOptions options) { 079 this.reader = asn1Reader; 080 this.options = options; 081 } 082 083 /** 084 * Returns the ASN.1 reader from which LDAP messages will be read. 085 * 086 * @return The ASN.1 reader from which LDAP messages will be read. 087 */ 088 public R getASN1Reader() { 089 return reader; 090 } 091 092 /** 093 * Returns {@code true} if the next LDAP message can be read without 094 * blocking. 095 * 096 * @return {@code true} if the next LDAP message can be read without 097 * blocking or {@code false} otherwise. 098 * @throws DecodeException 099 * If the available data was not a valid LDAP message. 100 * @throws IOException 101 * If an unexpected IO error occurred. 102 */ 103 public boolean hasMessageAvailable() throws DecodeException, IOException { 104 return reader.elementAvailable(); 105 } 106 107 /** 108 * Reads the next LDAP message from the underlying ASN.1 reader. 109 * 110 * @param handler 111 * The message handler which will handle the decoded LDAP 112 * message. 113 * @throws DecodeException 114 * If the available data was not a valid LDAP message. 115 * @throws IOException 116 * If an unexpected IO error occurred. 117 */ 118 public void readMessage(final LDAPMessageHandler handler) throws DecodeException, IOException { 119 reader.readStartSequence(); 120 try { 121 final int messageID = (int) reader.readInteger(); 122 readProtocolOp(messageID, handler); 123 } finally { 124 reader.readEndSequence(); 125 } 126 } 127 128 private void readAbandonRequest(final int messageID, final LDAPMessageHandler handler) 129 throws IOException { 130 final int msgToAbandon = (int) reader.readInteger(LDAP.OP_TYPE_ABANDON_REQUEST); 131 final AbandonRequest message = Requests.newAbandonRequest(msgToAbandon); 132 readControls(message); 133 logger.trace("DECODE LDAP ABANDON REQUEST(messageID=%d, request=%s)", messageID, message); 134 handler.abandonRequest(messageID, message); 135 } 136 137 private void readAddRequest(final int messageID, final LDAPMessageHandler handler) 138 throws IOException { 139 final Entry entry = LDAP.readEntry(reader, LDAP.OP_TYPE_ADD_REQUEST, options); 140 final AddRequest message = Requests.newAddRequest(entry); 141 readControls(message); 142 logger.trace("DECODE LDAP ADD REQUEST(messageID=%d, request=%s)", messageID, message); 143 handler.addRequest(messageID, message); 144 } 145 146 private void readAddResult(final int messageID, final LDAPMessageHandler handler) 147 throws IOException { 148 reader.readStartSequence(LDAP.OP_TYPE_ADD_RESPONSE); 149 final Result message; 150 try { 151 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 152 final String matchedDN = reader.readOctetStringAsString(); 153 final String diagnosticMessage = reader.readOctetStringAsString(); 154 message = 155 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 156 diagnosticMessage); 157 readResponseReferrals(message); 158 } finally { 159 reader.readEndSequence(); 160 } 161 readControls(message); 162 logger.trace("DECODE LDAP ADD RESULT(messageID=%d, result=%s)", messageID, message); 163 handler.addResult(messageID, message); 164 } 165 166 private void readBindRequest(final int messageID, final LDAPMessageHandler handler) 167 throws IOException { 168 reader.readStartSequence(LDAP.OP_TYPE_BIND_REQUEST); 169 try { 170 final int protocolVersion = (int) reader.readInteger(); 171 final String authName = reader.readOctetStringAsString(); 172 final byte authType = reader.peekType(); 173 final byte[] authBytes = reader.readOctetString(authType).toByteArray(); 174 final GenericBindRequest request = 175 Requests.newGenericBindRequest(authName, authType, authBytes); 176 readControls(request); 177 logger.trace("DECODE LDAP BIND REQUEST(messageID=%d, auth=0x%x, request=%s)", 178 messageID, request.getAuthenticationType(), request); 179 180 handler.bindRequest(messageID, protocolVersion, request); 181 } finally { 182 reader.readEndSequence(); 183 } 184 } 185 186 private void readBindResult(final int messageID, final LDAPMessageHandler handler) 187 throws IOException { 188 reader.readStartSequence(LDAP.OP_TYPE_BIND_RESPONSE); 189 final BindResult message; 190 try { 191 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 192 final String matchedDN = reader.readOctetStringAsString(); 193 final String diagnosticMessage = reader.readOctetStringAsString(); 194 message = 195 Responses.newBindResult(resultCode).setMatchedDN(matchedDN) 196 .setDiagnosticMessage(diagnosticMessage); 197 readResponseReferrals(message); 198 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_SERVER_SASL_CREDENTIALS)) { 199 message.setServerSASLCredentials(reader 200 .readOctetString(LDAP.TYPE_SERVER_SASL_CREDENTIALS)); 201 } 202 } finally { 203 reader.readEndSequence(); 204 } 205 readControls(message); 206 logger.trace("DECODE LDAP BIND RESULT(messageID=%d, result=%s)", messageID, message); 207 handler.bindResult(messageID, message); 208 } 209 210 private void readCompareRequest(final int messageID, final LDAPMessageHandler handler) 211 throws IOException { 212 reader.readStartSequence(LDAP.OP_TYPE_COMPARE_REQUEST); 213 final CompareRequest message; 214 try { 215 final String dnString = reader.readOctetStringAsString(); 216 final Schema schema = options.getSchemaResolver().resolveSchema(dnString); 217 final DN dn = LDAP.readDN(dnString, schema); 218 reader.readStartSequence(); 219 try { 220 final String ads = reader.readOctetStringAsString(); 221 final AttributeDescription ad = LDAP.readAttributeDescription(ads, schema); 222 final ByteString assertionValue = reader.readOctetString(); 223 message = Requests.newCompareRequest(dn, ad, assertionValue); 224 } finally { 225 reader.readEndSequence(); 226 } 227 } finally { 228 reader.readEndSequence(); 229 } 230 readControls(message); 231 logger.trace("DECODE LDAP COMPARE REQUEST(messageID=%d, request=%s)", messageID, message); 232 handler.compareRequest(messageID, message); 233 } 234 235 private void readCompareResult(final int messageID, final LDAPMessageHandler handler) 236 throws IOException { 237 reader.readStartSequence(LDAP.OP_TYPE_COMPARE_RESPONSE); 238 final CompareResult message; 239 try { 240 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 241 final String matchedDN = reader.readOctetStringAsString(); 242 final String diagnosticMessage = reader.readOctetStringAsString(); 243 message = 244 Responses.newCompareResult(resultCode).setMatchedDN(matchedDN) 245 .setDiagnosticMessage(diagnosticMessage); 246 readResponseReferrals(message); 247 } finally { 248 reader.readEndSequence(); 249 } 250 readControls(message); 251 logger.trace("DECODE LDAP COMPARE RESULT(messageID=%d, result=%s)", messageID, message); 252 handler.compareResult(messageID, message); 253 } 254 255 private Control readControl() throws IOException { 256 reader.readStartSequence(); 257 try { 258 final String oid = reader.readOctetStringAsString(); 259 final boolean isCritical; 260 if (reader.hasNextElement() && (reader.peekType() == ASN1.UNIVERSAL_BOOLEAN_TYPE)) { 261 isCritical = reader.readBoolean(); 262 } else { 263 isCritical = false; 264 } 265 final ByteString value; 266 if (reader.hasNextElement() && (reader.peekType() == ASN1.UNIVERSAL_OCTET_STRING_TYPE)) { 267 value = reader.readOctetString(); 268 } else { 269 value = null; 270 } 271 return GenericControl.newControl(oid, isCritical, value); 272 } finally { 273 reader.readEndSequence(); 274 } 275 } 276 277 private void readControls(final Request request) throws IOException { 278 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_CONTROL_SEQUENCE)) { 279 reader.readStartSequence(LDAP.TYPE_CONTROL_SEQUENCE); 280 try { 281 while (reader.hasNextElement()) { 282 request.addControl(readControl()); 283 } 284 } finally { 285 reader.readEndSequence(); 286 } 287 } 288 } 289 290 private void readControls(final Response response) throws IOException { 291 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_CONTROL_SEQUENCE)) { 292 reader.readStartSequence(LDAP.TYPE_CONTROL_SEQUENCE); 293 try { 294 while (reader.hasNextElement()) { 295 response.addControl(readControl()); 296 } 297 } finally { 298 reader.readEndSequence(); 299 } 300 } 301 } 302 303 private void readDeleteRequest(final int messageID, final LDAPMessageHandler handler) 304 throws IOException { 305 final String dnString = reader.readOctetStringAsString(LDAP.OP_TYPE_DELETE_REQUEST); 306 final Schema schema = options.getSchemaResolver().resolveSchema(dnString); 307 final DN dn = LDAP.readDN(dnString, schema); 308 final DeleteRequest message = Requests.newDeleteRequest(dn); 309 readControls(message); 310 logger.trace("DECODE LDAP DELETE REQUEST(messageID=%d, request=%s)", messageID, message); 311 handler.deleteRequest(messageID, message); 312 } 313 314 private void readDeleteResult(final int messageID, final LDAPMessageHandler handler) 315 throws IOException { 316 reader.readStartSequence(LDAP.OP_TYPE_DELETE_RESPONSE); 317 final Result message; 318 try { 319 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 320 final String matchedDN = reader.readOctetStringAsString(); 321 final String diagnosticMessage = reader.readOctetStringAsString(); 322 message = 323 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 324 diagnosticMessage); 325 readResponseReferrals(message); 326 } finally { 327 reader.readEndSequence(); 328 } 329 readControls(message); 330 logger.trace("DECODE LDAP DELETE RESULT(messageID=%d, result=%s)", messageID, message); 331 handler.deleteResult(messageID, message); 332 } 333 334 private void readExtendedRequest(final int messageID, final LDAPMessageHandler handler) 335 throws IOException { 336 reader.readStartSequence(LDAP.OP_TYPE_EXTENDED_REQUEST); 337 final GenericExtendedRequest message; 338 try { 339 final String oid = reader.readOctetStringAsString(LDAP.TYPE_EXTENDED_REQUEST_OID); 340 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_EXTENDED_REQUEST_VALUE)) { 341 final ByteString value = reader.readOctetString(LDAP.TYPE_EXTENDED_REQUEST_VALUE); 342 message = Requests.newGenericExtendedRequest(oid, value); 343 } else { 344 message = Requests.newGenericExtendedRequest(oid, null); 345 } 346 } finally { 347 reader.readEndSequence(); 348 } 349 readControls(message); 350 logger.trace("DECODE LDAP EXTENDED REQUEST(messageID=%d, request=%s)", messageID, message); 351 handler.extendedRequest(messageID, message); 352 } 353 354 private void readExtendedResult(final int messageID, final LDAPMessageHandler handler) 355 throws IOException { 356 reader.readStartSequence(LDAP.OP_TYPE_EXTENDED_RESPONSE); 357 final GenericExtendedResult message; 358 try { 359 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 360 final String matchedDN = reader.readOctetStringAsString(); 361 final String diagnosticMessage = reader.readOctetStringAsString(); 362 message = 363 Responses.newGenericExtendedResult(resultCode).setMatchedDN(matchedDN) 364 .setDiagnosticMessage(diagnosticMessage); 365 readResponseReferrals(message); 366 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_EXTENDED_RESPONSE_OID)) { 367 message.setOID(reader.readOctetStringAsString(LDAP.TYPE_EXTENDED_RESPONSE_OID)); 368 } 369 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_EXTENDED_RESPONSE_VALUE)) { 370 message.setValue(reader.readOctetString(LDAP.TYPE_EXTENDED_RESPONSE_VALUE)); 371 } 372 } finally { 373 reader.readEndSequence(); 374 } 375 readControls(message); 376 logger.trace("DECODE LDAP EXTENDED RESULT(messageID=%d, result=%s)", messageID, message); 377 handler.extendedResult(messageID, message); 378 } 379 380 private void readIntermediateResponse(final int messageID, final LDAPMessageHandler handler) 381 throws IOException { 382 reader.readStartSequence(LDAP.OP_TYPE_INTERMEDIATE_RESPONSE); 383 final GenericIntermediateResponse message; 384 try { 385 message = Responses.newGenericIntermediateResponse(); 386 if (reader.hasNextElement() 387 && (reader.peekType() == LDAP.TYPE_INTERMEDIATE_RESPONSE_OID)) { 388 message.setOID(reader.readOctetStringAsString(LDAP.TYPE_INTERMEDIATE_RESPONSE_OID)); 389 } 390 if (reader.hasNextElement() 391 && (reader.peekType() == LDAP.TYPE_INTERMEDIATE_RESPONSE_VALUE)) { 392 message.setValue(reader.readOctetString(LDAP.TYPE_INTERMEDIATE_RESPONSE_VALUE)); 393 } 394 } finally { 395 reader.readEndSequence(); 396 } 397 readControls(message); 398 logger.trace("DECODE LDAP INTERMEDIATE RESPONSE(messageID=%d, response=%s)", messageID, message); 399 handler.intermediateResponse(messageID, message); 400 } 401 402 private void readModifyDNRequest(final int messageID, final LDAPMessageHandler handler) 403 throws IOException { 404 reader.readStartSequence(LDAP.OP_TYPE_MODIFY_DN_REQUEST); 405 final ModifyDNRequest message; 406 try { 407 final String dnString = reader.readOctetStringAsString(); 408 final Schema schema = options.getSchemaResolver().resolveSchema(dnString); 409 final DN dn = LDAP.readDN(dnString, schema); 410 final String newRDNString = reader.readOctetStringAsString(); 411 final RDN newRDN = readRDN(newRDNString, schema); 412 message = Requests.newModifyDNRequest(dn, newRDN); 413 message.setDeleteOldRDN(reader.readBoolean()); 414 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_MODIFY_DN_NEW_SUPERIOR)) { 415 final String newSuperiorString = 416 reader.readOctetStringAsString(LDAP.TYPE_MODIFY_DN_NEW_SUPERIOR); 417 final DN newSuperior = LDAP.readDN(newSuperiorString, schema); 418 message.setNewSuperior(newSuperior); 419 } 420 } finally { 421 reader.readEndSequence(); 422 } 423 readControls(message); 424 logger.trace("DECODE LDAP MODIFY DN REQUEST(messageID=%d, request=%s)", messageID, message); 425 handler.modifyDNRequest(messageID, message); 426 } 427 428 private void readModifyDNResult(final int messageID, final LDAPMessageHandler handler) 429 throws IOException { 430 reader.readStartSequence(LDAP.OP_TYPE_MODIFY_DN_RESPONSE); 431 final Result message; 432 try { 433 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 434 final String matchedDN = reader.readOctetStringAsString(); 435 final String diagnosticMessage = reader.readOctetStringAsString(); 436 message = 437 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 438 diagnosticMessage); 439 readResponseReferrals(message); 440 } finally { 441 reader.readEndSequence(); 442 } 443 readControls(message); 444 logger.trace("DECODE LDAP MODIFY DN RESULT(messageID=%d, result=%s)", messageID, message); 445 handler.modifyDNResult(messageID, message); 446 } 447 448 private void readModifyRequest(final int messageID, final LDAPMessageHandler handler) 449 throws IOException { 450 reader.readStartSequence(LDAP.OP_TYPE_MODIFY_REQUEST); 451 final ModifyRequest message; 452 try { 453 final String dnString = reader.readOctetStringAsString(); 454 final Schema schema = options.getSchemaResolver().resolveSchema(dnString); 455 final DN dn = LDAP.readDN(dnString, schema); 456 message = Requests.newModifyRequest(dn); 457 reader.readStartSequence(); 458 try { 459 while (reader.hasNextElement()) { 460 reader.readStartSequence(); 461 try { 462 final int typeIntValue = reader.readEnumerated(); 463 final ModificationType type = ModificationType.valueOf(typeIntValue); 464 if (type == null) { 465 throw DecodeException 466 .error(ERR_LDAP_MODIFICATION_DECODE_INVALID_MOD_TYPE 467 .get(typeIntValue)); 468 } 469 reader.readStartSequence(); 470 try { 471 final String ads = reader.readOctetStringAsString(); 472 final AttributeDescription ad = 473 LDAP.readAttributeDescription(ads, schema); 474 final Attribute attribute = 475 options.getAttributeFactory().newAttribute(ad); 476 reader.readStartSet(); 477 try { 478 while (reader.hasNextElement()) { 479 attribute.add(reader.readOctetString()); 480 } 481 message.addModification(new Modification(type, attribute)); 482 } finally { 483 reader.readEndSet(); 484 } 485 } finally { 486 reader.readEndSequence(); 487 } 488 } finally { 489 reader.readEndSequence(); 490 } 491 } 492 } finally { 493 reader.readEndSequence(); 494 } 495 } finally { 496 reader.readEndSequence(); 497 } 498 readControls(message); 499 logger.trace("DECODE LDAP MODIFY REQUEST(messageID=%d, request=%s)", messageID, message); 500 handler.modifyRequest(messageID, message); 501 } 502 503 private void readModifyResult(final int messageID, final LDAPMessageHandler handler) 504 throws IOException { 505 reader.readStartSequence(LDAP.OP_TYPE_MODIFY_RESPONSE); 506 final Result message; 507 try { 508 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 509 final String matchedDN = reader.readOctetStringAsString(); 510 final String diagnosticMessage = reader.readOctetStringAsString(); 511 message = 512 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 513 diagnosticMessage); 514 readResponseReferrals(message); 515 } finally { 516 reader.readEndSequence(); 517 } 518 readControls(message); 519 logger.trace("DECODE LDAP MODIFY RESULT(messageID=%d, result=%s)", messageID, message); 520 handler.modifyResult(messageID, message); 521 } 522 523 private void readProtocolOp(final int messageID, final LDAPMessageHandler handler) 524 throws IOException { 525 final byte type = reader.peekType(); 526 switch (type) { 527 case LDAP.OP_TYPE_UNBIND_REQUEST: // 0x42 528 readUnbindRequest(messageID, handler); 529 break; 530 case LDAP.OP_TYPE_DELETE_REQUEST: // 0x4A 531 readDeleteRequest(messageID, handler); 532 break; 533 case LDAP.OP_TYPE_ABANDON_REQUEST: // 0x50 534 readAbandonRequest(messageID, handler); 535 break; 536 case LDAP.OP_TYPE_BIND_REQUEST: // 0x60 537 readBindRequest(messageID, handler); 538 break; 539 case LDAP.OP_TYPE_BIND_RESPONSE: // 0x61 540 readBindResult(messageID, handler); 541 break; 542 case LDAP.OP_TYPE_SEARCH_REQUEST: // 0x63 543 readSearchRequest(messageID, handler); 544 break; 545 case LDAP.OP_TYPE_SEARCH_RESULT_ENTRY: // 0x64 546 readSearchResultEntry(messageID, handler); 547 break; 548 case LDAP.OP_TYPE_SEARCH_RESULT_DONE: // 0x65 549 readSearchResult(messageID, handler); 550 break; 551 case LDAP.OP_TYPE_MODIFY_REQUEST: // 0x66 552 readModifyRequest(messageID, handler); 553 break; 554 case LDAP.OP_TYPE_MODIFY_RESPONSE: // 0x67 555 readModifyResult(messageID, handler); 556 break; 557 case LDAP.OP_TYPE_ADD_REQUEST: // 0x68 558 readAddRequest(messageID, handler); 559 break; 560 case LDAP.OP_TYPE_ADD_RESPONSE: // 0x69 561 readAddResult(messageID, handler); 562 break; 563 case LDAP.OP_TYPE_DELETE_RESPONSE: // 0x6B 564 readDeleteResult(messageID, handler); 565 break; 566 case LDAP.OP_TYPE_MODIFY_DN_REQUEST: // 0x6C 567 readModifyDNRequest(messageID, handler); 568 break; 569 case LDAP.OP_TYPE_MODIFY_DN_RESPONSE: // 0x6D 570 readModifyDNResult(messageID, handler); 571 break; 572 case LDAP.OP_TYPE_COMPARE_REQUEST: // 0x6E 573 readCompareRequest(messageID, handler); 574 break; 575 case LDAP.OP_TYPE_COMPARE_RESPONSE: // 0x6F 576 readCompareResult(messageID, handler); 577 break; 578 case LDAP.OP_TYPE_SEARCH_RESULT_REFERENCE: // 0x73 579 readSearchResultReference(messageID, handler); 580 break; 581 case LDAP.OP_TYPE_EXTENDED_REQUEST: // 0x77 582 readExtendedRequest(messageID, handler); 583 break; 584 case LDAP.OP_TYPE_EXTENDED_RESPONSE: // 0x78 585 readExtendedResult(messageID, handler); 586 break; 587 case LDAP.OP_TYPE_INTERMEDIATE_RESPONSE: // 0x79 588 readIntermediateResponse(messageID, handler); 589 break; 590 default: 591 handler.unrecognizedMessage(messageID, type, reader.readOctetString(type)); 592 break; 593 } 594 } 595 596 private RDN readRDN(final String rdn, final Schema schema) throws DecodeException { 597 try { 598 return RDN.valueOf(rdn, schema); 599 } catch (final LocalizedIllegalArgumentException e) { 600 throw DecodeException.error(e.getMessageObject()); 601 } 602 } 603 604 private void readResponseReferrals(final Result message) throws IOException { 605 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_REFERRAL_SEQUENCE)) { 606 reader.readStartSequence(LDAP.TYPE_REFERRAL_SEQUENCE); 607 try { 608 // Should have at least 1. 609 do { 610 message.addReferralURI((reader.readOctetStringAsString())); 611 } while (reader.hasNextElement()); 612 } finally { 613 reader.readEndSequence(); 614 } 615 } 616 } 617 618 private void readSearchRequest(final int messageID, final LDAPMessageHandler handler) 619 throws IOException { 620 reader.readStartSequence(LDAP.OP_TYPE_SEARCH_REQUEST); 621 final SearchRequest message; 622 try { 623 final String baseDNString = reader.readOctetStringAsString(); 624 final Schema schema = options.getSchemaResolver().resolveSchema(baseDNString); 625 final DN baseDN = LDAP.readDN(baseDNString, schema); 626 final int scopeIntValue = reader.readEnumerated(); 627 final SearchScope scope = SearchScope.valueOf(scopeIntValue); 628 if (scope == null) { 629 throw DecodeException.error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE 630 .get(scopeIntValue)); 631 } 632 final int dereferencePolicyIntValue = reader.readEnumerated(); 633 final DereferenceAliasesPolicy dereferencePolicy = 634 DereferenceAliasesPolicy.valueOf(dereferencePolicyIntValue); 635 if (dereferencePolicy == null) { 636 throw DecodeException.error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF 637 .get(dereferencePolicyIntValue)); 638 } 639 final int sizeLimit = (int) reader.readInteger(); 640 final int timeLimit = (int) reader.readInteger(); 641 final boolean typesOnly = reader.readBoolean(); 642 final Filter filter = LDAP.readFilter(reader); 643 message = Requests.newSearchRequest(baseDN, scope, filter); 644 message.setDereferenceAliasesPolicy(dereferencePolicy); 645 try { 646 message.setTimeLimit(timeLimit); 647 message.setSizeLimit(sizeLimit); 648 } catch (final LocalizedIllegalArgumentException e) { 649 throw DecodeException.error(e.getMessageObject()); 650 } 651 message.setTypesOnly(typesOnly); 652 reader.readStartSequence(); 653 try { 654 while (reader.hasNextElement()) { 655 message.addAttribute(reader.readOctetStringAsString()); 656 } 657 } finally { 658 reader.readEndSequence(); 659 } 660 } finally { 661 reader.readEndSequence(); 662 } 663 readControls(message); 664 logger.trace("DECODE LDAP SEARCH REQUEST(messageID=%d, request=%s)", messageID, message); 665 handler.searchRequest(messageID, message); 666 } 667 668 private void readSearchResult(final int messageID, final LDAPMessageHandler handler) 669 throws IOException { 670 reader.readStartSequence(LDAP.OP_TYPE_SEARCH_RESULT_DONE); 671 final Result message; 672 try { 673 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 674 final String matchedDN = reader.readOctetStringAsString(); 675 final String diagnosticMessage = reader.readOctetStringAsString(); 676 message = 677 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 678 diagnosticMessage); 679 readResponseReferrals(message); 680 } finally { 681 reader.readEndSequence(); 682 } 683 readControls(message); 684 logger.trace("DECODE LDAP SEARCH RESULT(messageID=%d, result=%s)", messageID, message); 685 handler.searchResult(messageID, message); 686 } 687 688 private void readSearchResultEntry(final int messageID, final LDAPMessageHandler handler) 689 throws IOException { 690 final Entry entry = LDAP.readEntry(reader, LDAP.OP_TYPE_SEARCH_RESULT_ENTRY, options); 691 final SearchResultEntry message = Responses.newSearchResultEntry(entry); 692 readControls(message); 693 logger.trace("DECODE LDAP SEARCH RESULT ENTRY(messageID=%d, entry=%s)", messageID, message); 694 handler.searchResultEntry(messageID, message); 695 } 696 697 private void readSearchResultReference(final int messageID, final LDAPMessageHandler handler) 698 throws IOException { 699 reader.readStartSequence(LDAP.OP_TYPE_SEARCH_RESULT_REFERENCE); 700 final SearchResultReference message; 701 try { 702 message = Responses.newSearchResultReference(reader.readOctetStringAsString()); 703 while (reader.hasNextElement()) { 704 message.addURI(reader.readOctetStringAsString()); 705 } 706 } finally { 707 reader.readEndSequence(); 708 } 709 readControls(message); 710 logger.trace("DECODE LDAP SEARCH RESULT REFERENCE(messageID=%d, reference=%s)", messageID, message); 711 handler.searchResultReference(messageID, message); 712 } 713 714 private void readUnbindRequest(final int messageID, final LDAPMessageHandler handler) 715 throws IOException { 716 reader.readNull(LDAP.OP_TYPE_UNBIND_REQUEST); 717 final UnbindRequest message = Requests.newUnbindRequest(); 718 readControls(message); 719 logger.trace("DECODE LDAP UNBIND REQUEST(messageID=%d, request=%s)", messageID, message); 720 handler.unbindRequest(messageID, message); 721 } 722}