]> git.sur5r.net Git - openldap/commitdiff
add paged results support to back-ldap
authorPierangelo Masarati <ando@openldap.org>
Tue, 24 Aug 2004 09:19:33 +0000 (09:19 +0000)
committerPierangelo Masarati <ando@openldap.org>
Tue, 24 Aug 2004 09:19:33 +0000 (09:19 +0000)
servers/slapd/back-bdb/search.c
servers/slapd/back-ldap/search.c
servers/slapd/controls.c

index 14975d9f367249bf61a6c4c23bba76cf50317dc8..fa80e81e01c8d4876bda7287df94f128196d32f3 100644 (file)
@@ -37,6 +37,8 @@ static int search_candidates(
        ID      *ids,
        ID      *scopes );
 
+static int parse_paged_cookie( Operation *op, SlapReply *rs );
+
 static void send_paged_response( 
        Operation *op,
        SlapReply *rs,
@@ -786,7 +788,14 @@ dn2entry_retry:
                tentries = BDB_IDL_N(candidates);
        }
 
-       if ( get_pagedresults(sop) > SLAP_NO_CONTROL ) {
+       if ( get_pagedresults( sop ) > SLAP_NO_CONTROL ) {
+               /* deferred cookie parsing */
+               rs->sr_err = parse_paged_cookie( sop, rs );
+               if ( rs->sr_err != LDAP_SUCCESS ) {
+                       send_ldap_result( sop, rs );
+                       goto done;
+               }
+
                if ( (ID)( sop->o_pagedresults_state.ps_cookie ) == 0 ) {
                        id = bdb_idl_first( candidates, &cursor );
 
@@ -1739,6 +1748,125 @@ static int search_candidates(
        return rc;
 }
 
+static int
+parse_paged_cookie( Operation *op, SlapReply *rs )
+{
+       LDAPControl     **c;
+       int             rc = LDAP_SUCCESS;
+       ber_tag_t       tag;
+       ber_int_t       size;
+       BerElement      *ber;
+       struct berval   cookie = BER_BVNULL;
+
+       /* this function must be invoked only if the pagedResults
+        * control has been detected, parsed and partially checked
+        * by the frontend */
+       assert( get_pagedresults( op ) > SLAP_NO_CONTROL );
+
+       /* look for the appropriate ctrl structure */
+       for ( c = op->o_ctrls; c[0] != NULL; c++ ) {
+               if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 )
+               {
+                       break;
+               }
+       }
+
+       if ( c[0] == NULL ) {
+               rs->sr_text = "missing pagedResults control";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       /* Already tested by frontend */
+       assert( c[0]->ldctl_value.bv_len > 0 );
+#if 0
+       if ( c[0]->ldctl_value.bv_len == 0 ) {
+               rs->sr_text = "paged results control value is empty (or absent)";
+               return LDAP_PROTOCOL_ERROR;
+       }
+#endif
+
+       /* Parse the control value
+        *      realSearchControlValue ::= SEQUENCE {
+        *              size    INTEGER (0..maxInt),
+        *                              -- requested page size from client
+        *                              -- result set size estimate from server
+        *              cookie  OCTET STRING
+        * }
+        */
+       ber = ber_init( &c[0]->ldctl_value );
+       if ( ber == NULL ) {
+               rs->sr_text = "internal error";
+               return LDAP_OTHER;
+       }
+
+       tag = ber_scanf( ber, "{im}", &size, &cookie );
+
+       /* Already tested by frontend */
+       assert( tag != LBER_ERROR );
+#if 0
+       if ( tag == LBER_ERROR ) {
+               rs->sr_text = "paged results control could not be decoded";
+               rc = LDAP_PROTOCOL_ERROR;
+               goto done;
+       }
+#endif
+
+       /* Already tested by frontend */
+       assert( size >= 0 );
+#if 0
+       if ( size < 0 ) {
+               rs->sr_text = "paged results control size invalid";
+               rc = LDAP_PROTOCOL_ERROR;
+               goto done;
+       }
+#endif
+
+       /* cookie decoding/checks deferred to backend... */
+       if ( cookie.bv_len ) {
+               PagedResultsCookie reqcookie;
+               if( cookie.bv_len != sizeof( reqcookie ) ) {
+                       /* bad cookie */
+                       rs->sr_text = "paged results cookie is invalid";
+                       rc = LDAP_PROTOCOL_ERROR;
+                       goto done;
+               }
+
+               AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
+
+               if ( reqcookie > op->o_pagedresults_state.ps_cookie ) {
+                       /* bad cookie */
+                       rs->sr_text = "paged results cookie is invalid";
+                       rc = LDAP_PROTOCOL_ERROR;
+                       goto done;
+
+               } else if ( reqcookie < op->o_pagedresults_state.ps_cookie ) {
+                       rs->sr_text = "paged results cookie is invalid or old";
+                       rc = LDAP_UNWILLING_TO_PERFORM;
+                       goto done;
+               }
+
+       } else {
+               /* Initial request.  Initialize state. */
+#if 0
+               if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) {
+                       /* There's another pagedResults control on the
+                        * same connection; reject new pagedResults controls 
+                        * (allowed by RFC2696) */
+                       rs->sr_text = "paged results cookie unavailable; try later";
+                       rc = LDAP_UNWILLING_TO_PERFORM;
+                       goto done;
+               }
+#endif
+               op->o_pagedresults_state.ps_cookie = 0;
+               op->o_pagedresults_state.ps_count = 0;
+       }
+
+done:;
+       (void)ber_free( ber, 1 );
+
+       return rc;
+}
+
 static void
 send_paged_response( 
        Operation       *op,
index 753d7fa6ab95ba3e84a5a84fc33c97f80e48fc3f..6711fab063c2c53ba5f5e7c298da05f2b889c42e 100644 (file)
@@ -260,7 +260,7 @@ fail:;
                } else {
                        rc = ldap_parse_result( lc->ld, res, &rs->sr_err,
                                        &match.bv_val, (char **)&rs->sr_text,
-                                       NULL, NULL, 1 );
+                                       NULL, &rs->sr_ctrls, 1 );
                        if (rc != LDAP_SUCCESS ) {
                                rs->sr_err = rc;
                        }
@@ -307,6 +307,11 @@ finish:;
        }
 #endif /* LDAP_BACK_PROXY_AUTHZ */
 
+       if ( rs->sr_ctrls ) {
+               ldap_controls_free( rs->sr_ctrls );
+               rs->sr_ctrls = NULL;
+       }
+
        if ( match.bv_val ) {
                if ( rs->sr_matched != match.bv_val ) {
                        free( (char *)rs->sr_matched );
index 097bfd49643806b0e7449124f3e5ef7c105cec97..21818c04968ecfa291fc658a2341c438d99d1d03 100644 (file)
@@ -873,26 +873,28 @@ static int parsePagedResults (
         * }
         */
        ber = ber_init( &ctrl->ldctl_value );
-       if( ber == NULL ) {
+       if ( ber == NULL ) {
                rs->sr_text = "internal error";
                return LDAP_OTHER;
        }
 
        tag = ber_scanf( ber, "{im}", &size, &cookie );
 
-       if( tag == LBER_ERROR ) {
+       if ( tag == LBER_ERROR ) {
                rs->sr_text = "paged results control could not be decoded";
                rc = LDAP_PROTOCOL_ERROR;
                goto done;
        }
 
-       if( size < 0 ) {
+       if ( size < 0 ) {
                rs->sr_text = "paged results control size invalid";
                rc = LDAP_PROTOCOL_ERROR;
                goto done;
        }
 
-       if( cookie.bv_len ) {
+#if 0
+       /* defer cookie decoding/checks to backend... */
+       if ( cookie.bv_len ) {
                PagedResultsCookie reqcookie;
                if( cookie.bv_len != sizeof( reqcookie ) ) {
                        /* bad cookie */
@@ -930,6 +932,7 @@ static int parsePagedResults (
                op->o_pagedresults_state.ps_cookie = 0;
                op->o_pagedresults_state.ps_count = 0;
        }
+#endif
 
        op->o_pagedresults_size = size;